All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] Add support for Ultrasoc Trace Module
@ 2021-06-15  9:34 Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers Qi Liu
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Qi Liu @ 2021-06-15  9:34 UTC (permalink / raw)
  To: alexander.shishkin, mathieu.poirier, suzuki.poulose,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight, linuxarm, liuqi115

This patchset adds support for Ultrasoc Trace Module on Hip08 and Hip09
platform. It includes core layer framework, AXI Communicator(AXI-COM) and 
System Memory Buffer(SMB).

Qi Liu (4):
  Documentation: tracing: Documentation for ultrasoc framework and drivers
  ultrasoc: add ultrasoc core layer framework
  ultrasoc: Add ultrasoc AXI Communicator driver
  ultrasoc: Add System Memory Buffer driver

 Documentation/trace/ultrasoc-trace.rst        | 209 ++++++++
 MAINTAINERS                                   |   7 +
 drivers/Makefile                              |   1 +
 drivers/hwtracing/Kconfig                     |   2 +
 drivers/hwtracing/ultrasoc/Kconfig            |  34 ++
 drivers/hwtracing/ultrasoc/Makefile           |  13 +
 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c | 334 +++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h |  66 +++
 drivers/hwtracing/ultrasoc/ultrasoc-smb.c     | 663 ++++++++++++++++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc-smb.h     | 182 +++++++
 drivers/hwtracing/ultrasoc/ultrasoc.c         | 518 ++++++++++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc.h         | 168 +++++++
 12 files changed, 2197 insertions(+)
 create mode 100644 Documentation/trace/ultrasoc-trace.rst
 create mode 100644 drivers/hwtracing/ultrasoc/Kconfig
 create mode 100644 drivers/hwtracing/ultrasoc/Makefile
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers
  2021-06-15  9:34 [RFC PATCH 0/4] Add support for Ultrasoc Trace Module Qi Liu
@ 2021-06-15  9:34 ` Qi Liu
  2021-06-23 22:51   ` Mathieu Poirier
  2021-06-15  9:34 ` [RFC PATCH 2/4] ultrasoc: add ultrasoc core layer framework Qi Liu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 16+ messages in thread
From: Qi Liu @ 2021-06-15  9:34 UTC (permalink / raw)
  To: alexander.shishkin, mathieu.poirier, suzuki.poulose,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight, linuxarm, liuqi115

Ultrasoc trace module is a system level solution for both core tracing
and SoC tracing. This patch brings in a documentation for ultrasoc
framework and drivers. It simply introduces function of ultrasoc, a
typical Ultrasoc system, and a driver framework for ultrasoc.

Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
---
 Documentation/trace/ultrasoc-trace.rst | 209 +++++++++++++++++++++++++++++++++
 1 file changed, 209 insertions(+)
 create mode 100644 Documentation/trace/ultrasoc-trace.rst

diff --git a/Documentation/trace/ultrasoc-trace.rst b/Documentation/trace/ultrasoc-trace.rst
new file mode 100644
index 0000000..36d2df2
--- /dev/null
+++ b/Documentation/trace/ultrasoc-trace.rst
@@ -0,0 +1,209 @@
+=======================================================
+Siemens Embedded Analytics - HW Assisted Tracing on SoC
+=======================================================
+   :Author:   Jonathan Zhou <Jonathan.zhouwen@huawei.com>
+              Qi Liu <liuqi115@huawei.com>
+   :Date:     January 16th, 2021
+
+Introduction
+------------
+
+The Siemens Embedded Analytics Framework is system level solution for tracing
+of multiple type SoC, this document is concerned with trace module. This module
+has two main components: AXI Bus Communicator and System Memory Buffer.
+
+The AXI Communicator has upstream and downstream channels, the upstream channel
+is used to transmit user configuration, and downstream channel to carry response
+and trace data to the users.
+
+The System Memory Buffer provides a way to buffer and store messages in system
+memory. It provides a capability to store messages received on its input message
+interface to an area of system memory.
+
+A typical Siemens trace system would look like the following diagram:
+                           @@@@@@@@@@@@@
+                           @    CPU    @
+                           @@@@@@@@@@@@@
+                           #############
+                           # Coresight #
+                             #  ETM  #
+                              #######
+                                ###
+                                 #
+                                 |
+                                 *
+                    *******************************
+                 *** AMBA Advanced Trace Bus (ATB) ***
+                    ***************^***************
+                          ===============    |
+                           === FUNNEL ==<--- |
+                              =======
+                                 |
+                                 *
+                              @@@@@@@
+                              @ TRC @
+                               @@@@@
+                                @@@
+                                 @
+                                 |
+                                 *
+    ************************************** *******************
+ ************************ Message BUS ***************************
+    ******************^************************^****************
+             |                               |
+     @@@@@@@@@@@@@@@@@@                      |   @@@@@@@@@@@@
+     @ Message Engine @                      |   @ JTAG COM @
+     @@@@@@@@@@@@@@@@@@                      |    @@@@@@@@@@
+       |            *                        |---> @@@@@@@@
+       |            |                               @@@@@@
+    @@@@@@@         |   @@@@@@@@@@@                    |
+    @ SMB @         |   @ AXI COM @                  JTAG
+     @@@@@          |--> @@@@@@@@@
+      @@@--|              @@@@@@@
+       @   |               @@@@@
+           |                 |
+           |                 |
+           *                 *
+  ***************************************************************
+ **************************** AMBA AXI  ****************************
+  *****************************************************************
+
+Acronyms
+---------------------------
+
+Acronyms:
+
+AXI-COM:     AXI Communicator
+SMB:         System Memory Buffer
+TRC:         Trace receiver
+
+Framework and implementation
+------------------------------
+
+Siemens Embedded Analytics Framework is implemented as a platform device. The
+platform device provides a global point to configure the Embedded Analytics
+subsystem, and also provides a ``struct ultrasoc_com`` to manage AXI-COM and
+SMB.
+
+AXI-COM and SMB are implemented as platform devices, each SCCL has one AXI-COM
+device and one SMB device. AXI-COM and SMB can use the following API to register
+into Embedded Analytics framework:
+.. c:function:: struct ultrasoc_com *ultrasoc_register_com(struct device *root_dev, struct ultrasoc_com_descp *com_descp)
+.. c:function:: void ultrasoc_unregister_com(struct ultrasoc_com *com);
+
+As TRC receives data from coresight ETM device, SMB can use the following API
+to register into coresight framework as a sink device:
+.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc);
+.. c:function:: void coresight_unregister(struct coresight_device *csdev);
+
+Then users can get trace data by this path: ETM->funnel->SMB->System Memory.
+More information about coresight framework can be found in
+Documention/trace/coresight/coresight.rst.
+
+If everything goes well, the relationship of Embedded Analytics devices will be
+described under the sysfs::
+
+    $# ls /sys/bus/platform/devices/
+    <HID.Embedded Analytics>:00   <HID.axi-com>:00   <HID.smb>:00
+    $# ls /sys/bus/platform/devices/<HID.Embedded Analytics>:00
+    com_mux             firmware_node     power      <HID.axi-com>:00
+    driver              message           subsystem  <HID.smb>:00
+    driver_override     modalias          uevent
+    $# ls /sys/bus/coresight/devices/
+    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
+    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
+    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
+    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
+    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
+    etm13    etm19    etm24    etm3     etm7     funnel3
+    $# ls -l /sys/bus/coresight/devices/funnel0/connections/
+    <file details> in:0 -> ../../../../system/cpu/cpu0/ARMHC500:00/etm0
+    <file details> in:1 -> ../../../../system/cpu/cpu1/ARMHC500:01/etm1
+    <file details> in:2 -> ../../../../system/cpu/cpu2/ARMHC500:02/etm2
+    <file details> in:3 -> ../../../../system/cpu/cpu3/ARMHC500:03/etm3
+    <file details> nr_links
+    <file details> out:0 -> ../../../HISI0391:00/HISI03A1:00/sink_smb0
+    $# ls -l /sys/bus/coresight/devices/sink_smb0/connections/
+    <file details>  in:101 -> ../../../../ARMHC9FE:05/funnel5
+    <file details>  in:114 -> ../../../../ARMHC9FE:07/funnel7
+    <file details>  in:121 -> ../../../../ARMHC9FE:03/funnel3
+    <file details>  in:39 -> ../../../../ARMHC9FE:00/funnel0
+    <file details>  in:51 -> ../../../../ARMHC9FE:04/funnel4
+    <file details>  in:61 -> ../../../../ARMHC9FE:06/funnel6
+    <file details>  in:68 -> ../../../../ARMHC9FE:02/funnel2
+    <file details>  in:89 -> ../../../../ARMHC9FE:01/funnel1
+    <file details>  nr_links
+
+How to use the Embedded Analytics trace module
+-----------------------------------------------
+
+There are two ways to use the Embedded Analytics trace module:
+
+1. interacting directly with the devices using the sysFS interface.
+2. using the perf cmd line tools.
+
+1) Using the sysFS interface:
+
+Before trace collection can start, a coresight sink needs to be identified.
+There is no limit on the amount of sinks (nor sources) that can be enabled at
+any given moment.  As a generic operation, all device pertaining to the sink
+class will have an "active" entry in sysfs::
+
+    $# ls /sys/bus/coresight/devices/
+    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
+    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
+    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
+    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
+    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
+    etm13    etm19    etm24    etm3     etm7     funnel3
+    $# ls /sys/bus/coresight/devices/sink_smb0
+    connections  enable_sink  firmware_node  power  subsystem  uevent
+    $# echo 1 > /sys/bus/coresight/devices/sink_smb0/enable_sink
+    $# cat /sys/bus/coresight/devices/sink_smb0/enable_sink
+    1
+
+When start trace collection, etm devices corresponding to the enabled sink
+should be selected::
+
+    $# echo 1 > /sys/bus/coresight/devices/etm0/enable_source
+    $# cat /sys/bus/coresight/devices/etm0/enable_source
+    1
+    $# cat /sys/bus/platform/devices/<HID.smb>:00/com_status
+    com-type            : DOWN-ONLY
+    service status      : stopped
+    interrupt status    : 0x00000003
+    write point         : 0x5437f400   <----- The write pointer is moving
+
+Trace collection is stopped the same way::
+
+    $# echo 0 > /sys/bus/coresight/devices/etm0/enable_source
+    $# echo 0 > /sys/bus/coresight/devices/sink_smb0/enable_sink
+
+The content of the SMB buffer can be harvested directly from /dev::
+
+    $# dd if=/dev/sink_smb0 of=~/cstrace.bin
+    5233+0 records in
+    5233+0 records out
+    2679296 bytes (2.7 MB) copied, 0.0131708 s, 203 MB/s
+
+    root:/sys/bus/coresight/devices#
+
+The file cstrace.bin can be decompressed using "ptm2human".
+
+2) Using perf framework:
+
+As SMB device has been registered with coresight framework, perf tool can be
+used to control Embedded Analytics trace collection, and the method is similar
+to using perf to do coresight trace collection.
+
+The only thing to note is, list of cpus should be correspond to the specified
+sink device.
+
+Example usage of perf::
+
+	 $# ./perf list pmu
+	 cs_etm//                                    [Kernel PMU event]
+    $# ./perf record -e cs_etm/@sink_smb0/ -C 0 --per-thread sleep 2s
+    [ perf record: Woken up 2 times to write data ]
+    [ perf record: Captured and wrote 0.288 MB perf.data ]
+    $# ./perf report
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC PATCH 2/4] ultrasoc: add ultrasoc core layer framework
  2021-06-15  9:34 [RFC PATCH 0/4] Add support for Ultrasoc Trace Module Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers Qi Liu
@ 2021-06-15  9:34 ` Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
  3 siblings, 0 replies; 16+ messages in thread
From: Qi Liu @ 2021-06-15  9:34 UTC (permalink / raw)
  To: alexander.shishkin, mathieu.poirier, suzuki.poulose,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight, linuxarm, liuqi115

This patch introduces a platform driver for the top device of Ultrasoc
SubSystem. It also provides a framework to manage Ultrasoc communictors,
and a set of standard attributes of communicators to access the service
data and to configure the communictor drivers.
Once a Ultrasoc Communictor driver register itself into the framework,
these attributes will be added into communicator devices.

Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
---
 MAINTAINERS                           |   7 +
 drivers/Makefile                      |   1 +
 drivers/hwtracing/Kconfig             |   2 +
 drivers/hwtracing/ultrasoc/Kconfig    |  16 ++
 drivers/hwtracing/ultrasoc/Makefile   |   7 +
 drivers/hwtracing/ultrasoc/ultrasoc.c | 518 ++++++++++++++++++++++++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc.h | 168 +++++++++++
 7 files changed, 719 insertions(+)
 create mode 100644 drivers/hwtracing/ultrasoc/Kconfig
 create mode 100644 drivers/hwtracing/ultrasoc/Makefile
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 88c2c4d..d799f6e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8324,6 +8324,13 @@ S:	Maintained
 F:	drivers/misc/hisi_hikey_usb.c
 F:	Documentation/devicetree/bindings/misc/hisilicon-hikey-usb.yaml
 
+SIEMENS EMBEDDED ANALYTICS DRIVER
+M:	Jonathan Zhou <Jonathan.zhouwen@huawei.com>
+M:	Qi Liu <liuqi115@huawei.com>
+S:	Supported
+F:	Documentation/trace/ultrasoc-trace.rst
+F:	drivers/hwtracing/ultrasoc/
+
 HISILICON PMU DRIVER
 M:	Shaokun Zhang <zhangshaokun@hisilicon.com>
 S:	Supported
diff --git a/drivers/Makefile b/drivers/Makefile
index 5a6d613..4c132a7 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -176,6 +176,7 @@ obj-$(CONFIG_PERF_EVENTS)	+= perf/
 obj-$(CONFIG_RAS)		+= ras/
 obj-$(CONFIG_USB4)		+= thunderbolt/
 obj-$(CONFIG_CORESIGHT)		+= hwtracing/coresight/
+obj-y				+= hwtracing/ultrasoc/
 obj-y				+= hwtracing/intel_th/
 obj-$(CONFIG_STM)		+= hwtracing/stm/
 obj-$(CONFIG_ANDROID)		+= android/
diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig
index 1308583..3829030 100644
--- a/drivers/hwtracing/Kconfig
+++ b/drivers/hwtracing/Kconfig
@@ -5,4 +5,6 @@ source "drivers/hwtracing/stm/Kconfig"
 
 source "drivers/hwtracing/intel_th/Kconfig"
 
+source "drivers/hwtracing/ultrasoc/Kconfig"
+
 endmenu
diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
new file mode 100644
index 0000000..90a3934
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: MIT
+#
+# ultrasoc configuration
+#
+
+menuconfig ULTRASOC
+	tristate "Ultrasoc Tracing Support"
+	select CORESIGHT
+	help
+	  This framework provides a kernel interface for the Ultrasoc trace
+	  drivers to register themselves with. It's intended to build
+	  a topological view of the Ultrasoc components based on ACPI
+	  specification and configure the right series of components when a
+	  trace source gets enabled.
+
+endif
diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
new file mode 100644
index 0000000..a747171
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/Makefile
@@ -0,0 +1,7 @@
+# # SPDX-License-Identifier: MIT
+#
+# Makefile for ultrasoc drivers.
+#
+
+obj-$(CONFIG_ULTRASOC) += ultrasoc-drv.o
+ultrasoc-drv-objs := ultrasoc.o
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc.c b/drivers/hwtracing/ultrasoc/ultrasoc.c
new file mode 100644
index 0000000..191c3ec
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc.c
@@ -0,0 +1,518 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "ultrasoc.h"
+
+static ssize_t com_mux_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t size)
+{
+	struct ultrasoc_drv_data *drvdata = dev_get_drvdata(dev);
+	long val;
+	int ret;
+
+	ret = kstrtol(buf, 0, &val);
+	if (ret)
+		return -EINVAL;
+
+	writel(val & 0xffffffff, drvdata->com_mux);
+	return size;
+}
+
+static ssize_t com_mux_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct ultrasoc_drv_data *drvdata = dev_get_drvdata(dev);
+
+	return sysfs_emit(buf, "0x%x\n", readl(drvdata->com_mux));
+}
+static DEVICE_ATTR_RW(com_mux);
+
+static umode_t ultrasoc_com_mux_is_visible(struct kobject *kobj,
+					   struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct ultrasoc_drv_data *drvdata = dev_get_drvdata(dev);
+
+	if (IS_ERR(drvdata->com_mux))
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute *ultrasoc_com_mux_attr[] = {
+	&dev_attr_com_mux.attr,
+	NULL,
+};
+
+static const struct attribute_group ultrasoc_com_mux_group = {
+	.attrs = ultrasoc_com_mux_attr,
+	.is_visible = ultrasoc_com_mux_is_visible,
+};
+
+static const struct attribute_group *ultrasoc_global_groups[] = {
+	&ultrasoc_com_mux_group,
+	NULL,
+};
+
+static int ultrasoc_probe(struct platform_device *pdev)
+{
+	struct ultrasoc_drv_data *drvdata;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+	drvdata->dev = &pdev->dev;
+	INIT_LIST_HEAD(&drvdata->ultrasoc_com_head);
+
+	drvdata->com_mux = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(drvdata->com_mux)) {
+		dev_err(&pdev->dev, "Failed to ioremap for com_mux resource.\n");
+		return PTR_ERR(drvdata->com_mux);
+	}
+	/* switch ultrasoc commucator mux for on-chip drivers. */
+	writel(US_SELECT_ONCHIP, drvdata->com_mux);
+	platform_set_drvdata(pdev, drvdata);
+
+	return 0;
+}
+
+static int ultrasoc_remove(struct platform_device *pdev)
+{
+	struct ultrasoc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	/* switch back to external debuger users if necessary.*/
+	if (!IS_ERR(pdata->com_mux))
+		writel(0, pdata->com_mux);
+
+	return 0;
+}
+
+static struct acpi_device_id ultrasoc_acpi_match[] = {
+	{"HISI0391", },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, ultrasoc_acpi_match);
+
+static struct platform_driver ultrasoc_driver = {
+	.driver = {
+		.name = "ultrasoc",
+		.acpi_match_table = ultrasoc_acpi_match,
+		.dev_groups = ultrasoc_global_groups,
+	},
+	.probe = ultrasoc_probe,
+	.remove = ultrasoc_remove,
+};
+module_platform_driver(ultrasoc_driver);
+
+static const char * const ultrasoc_com_type_string[] = {
+	"UNKNOWN",
+	"UP-DOWN-BOTH",
+	"DOWN-ONLY",
+};
+
+static const char * const ultrasoc_com_service_status_string[] = {
+	"stopped",
+	"sleeping",
+	"running normal",
+};
+
+/*
+ * To avoid communicator buffer overflow, we create a service thread
+ * to do the communicator work. This is the service thread entry.
+ */
+static int ultrasoc_com_service(void *arg)
+{
+	unsigned int deep_sleep = 0;
+	struct ultrasoc_com *com;
+	int ud_flag = 0;
+	int core;
+
+	core = smp_processor_id();
+	com = (struct ultrasoc_com *)arg;
+	if (!com->com_work) {
+		dev_err(com->dev,
+			 "This communicator do not have a work entry.\n");
+		com->service_status = ULTRASOC_COM_SERVICE_STOPPED;
+		return -EINVAL;
+	}
+	dev_dbg(com->dev, "ultrasoc com service %s run on core %d.\n",
+		com->name,  core);
+
+	while (true) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock(&com->service_lock);
+		if (com->service_status == ULTRASOC_COM_SERVICE_SLEEPING) {
+			spin_unlock(&com->service_lock);
+			schedule();
+			spin_lock(&com->service_lock);
+		}
+
+		/*
+		 * Since this thread service might be woken up with a status
+		 * of STOP, we check the status again to avoid setting an error
+		 * status
+		 */
+		if (com->service_status == ULTRASOC_COM_SERVICE_SLEEPING) {
+			com->service_status =
+				ULTRASOC_COM_SERVICE_RUNNING_NORMAL;
+			deep_sleep = 0;
+		}
+		spin_unlock(&com->service_lock);
+		__set_current_state(TASK_RUNNING);
+
+		if (com->service_status == ULTRASOC_COM_SERVICE_STOPPED)
+			break;
+
+		ud_flag = com->com_work(com);
+		if (!ud_flag) {
+			usleep_range(10, 100);
+			deep_sleep++;
+		} else {
+			deep_sleep = 0;
+			usleep_range(1, 4);
+		}
+		if (deep_sleep > com->timeout)
+			com->service_status = ULTRASOC_COM_SERVICE_SLEEPING;
+		if (kthread_should_stop())
+			break;
+	}
+	com->service_status = ULTRASOC_COM_SERVICE_STOPPED;
+
+	return 0;
+}
+
+static void com_try_stop_service(struct ultrasoc_com *com)
+{
+	if (com->service_status != ULTRASOC_COM_SERVICE_STOPPED) {
+		spin_lock(&com->service_lock);
+		com->service_status = ULTRASOC_COM_SERVICE_STOPPED;
+		spin_unlock(&com->service_lock);
+		kthread_stop(com->service);
+		com->service = NULL;
+	}
+}
+
+static void com_try_start_service(struct ultrasoc_com *com)
+{
+	if (com->service &&
+	    com->service_status != ULTRASOC_COM_SERVICE_STOPPED) {
+		dev_notice(com->dev, "Service is already running on %ld.\n",
+			   com->core_bind);
+		wake_up_process(com->service);
+		return;
+	}
+
+	dev_dbg(com->dev, "Starting service %s on core %ld.\n",	com->name,
+		com->core_bind);
+	com->service = kthread_create(ultrasoc_com_service, com, "%s_service",
+				      com->name);
+	if (IS_ERR(com->service)) {
+		spin_lock(&com->service_lock);
+		com->service_status = ULTRASOC_COM_SERVICE_STOPPED;
+		spin_unlock(&com->service_lock);
+		dev_err(com->dev, "Failed to start service.\n");
+	}
+
+	if (com->core_bind != -1)
+		kthread_bind(com->service, com->core_bind);
+
+	spin_lock(&com->service_lock);
+	com->service_status = ULTRASOC_COM_SERVICE_RUNNING_NORMAL;
+	spin_unlock(&com->service_lock);
+	wake_up_process(com->service);
+}
+
+static void com_service_restart(struct ultrasoc_com *com)
+{
+	com_try_stop_service(com);
+	com_try_start_service(com);
+}
+
+static ssize_t ultrasoc_com_status(struct ultrasoc_com *com, char *buf)
+{
+	enum ultrasoc_com_service_status status = com->service_status;
+	enum ultrasoc_com_type type = com->com_type;
+	ssize_t wr_size;
+
+	wr_size = sysfs_emit(buf, "%-20s: %s\n", "com-type",
+			     ultrasoc_com_type_string[type]);
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %s\n", "service status",
+				 ultrasoc_com_service_status_string[status]);
+	wr_size += uscom_ops_com_status(com, buf, wr_size);
+
+	return wr_size;
+}
+
+ULTRASOC_COM_ATTR_WO_OPS(start, com_try_start_service);
+ULTRASOC_COM_ATTR_WO_OPS(stop, com_try_stop_service);
+ULTRASOC_COM_ATTR_WO_OPS(restart, com_service_restart);
+ULTRASOC_COM_ATTR_RO_OPS(com_status, ultrasoc_com_status);
+
+struct ultrasoc_com *ultrasoc_find_com_by_dev(struct device *com_dev)
+{
+	struct ultrasoc_drv_data *pdata = dev_get_drvdata(com_dev->parent);
+	struct list_head *com_head = &pdata->ultrasoc_com_head;
+	struct ultrasoc_com *com;
+	struct list_head *cur;
+
+	list_for_each(cur, com_head) {
+		com = list_entry(cur, struct ultrasoc_com, node);
+		if (com->dev == com_dev)
+			return com;
+	}
+
+	dev_err(com_dev, "Unable to find com associated with this device!\n");
+	return NULL;
+}
+
+static ssize_t core_bind_store(struct device *dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t size)
+{
+	struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);
+	long core_bind;
+	int ret;
+
+	if (!com)
+		return 0;
+
+	ret = kstrtol(buf, 0, &core_bind);
+	if (!ret)
+		com->core_bind = core_bind;
+
+	return size;
+}
+
+static ssize_t core_bind_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);
+
+	if (!com)
+		return 0;
+
+	return sysfs_emit(buf, "%#lx", com->core_bind);
+}
+static DEVICE_ATTR_RW(core_bind);
+
+static ssize_t message_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t size)
+{
+	struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);
+	u64 msg, msg_len;
+	int elements;
+
+	elements = sscanf(buf, "%llx %llx", &msg, &msg_len);
+	if (elements < 2)
+		return -EINVAL;
+
+	com->com_ops->put_raw_msg(com, msg_len, msg);
+	dev_dbg(dev, "Set message %#llx, length is %#llx.\n", msg, msg_len);
+
+	return size;
+}
+static DEVICE_ATTR_WO(message);
+
+static umode_t ultrasoc_com_message_is_visible(struct kobject *kobj,
+					   struct attribute *attr, int unused)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);
+
+	if (com->com_type != ULTRASOC_COM_TYPE_BOTH)
+		return 0;
+
+	return attr->mode;
+}
+
+static struct attribute *ultrasoc_com_global_attrs[] = {
+	&dev_attr_com_status.attr,
+	NULL,
+};
+
+static struct attribute *ultrasoc_com_service_attrs[] = {
+	&dev_attr_core_bind.attr,
+	&dev_attr_start.attr,
+	&dev_attr_stop.attr,
+	&dev_attr_restart.attr,
+	NULL,
+};
+
+static struct attribute *ultrasoc_com_message_attrs[] = {
+	&dev_attr_message.attr,
+	NULL,
+};
+
+static const struct attribute_group ultrasoc_com_global_group = {
+	.attrs = ultrasoc_com_global_attrs,
+};
+
+static const struct attribute_group ultrasoc_com_service_group = {
+	.attrs = ultrasoc_com_service_attrs,
+	.name = "service",
+};
+
+static const struct attribute_group ultrasoc_com_message_group = {
+	.attrs = ultrasoc_com_message_attrs,
+	.is_visible = ultrasoc_com_message_is_visible,
+};
+
+static const struct attribute_group *ultrasoc_com_attr[] = {
+	&ultrasoc_com_global_group,
+	&ultrasoc_com_service_group,
+	&ultrasoc_com_message_group,
+	NULL,
+};
+
+static int ultrasoc_validate_com_descp(struct ultrasoc_com_descp *com_descp)
+{
+	if (!com_descp->uscom_ops)
+		return -EINVAL;
+
+	if (com_descp->com_type == ULTRASOC_COM_TYPE_BOTH) {
+		if (!com_descp->uscom_ops->put_raw_msg ||
+		    !com_descp->default_route_msg)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wait_com_service_stop(struct ultrasoc_com *com)
+{
+	u32 timeout = 0;
+
+	if (com->service_status != ULTRASOC_COM_SERVICE_STOPPED)
+		com_try_stop_service(com);
+	while (com->service_status != ULTRASOC_COM_SERVICE_STOPPED) {
+		usleep_range(10, 100);
+		timeout++;
+		if (timeout > com->timeout)
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/**
+ * ultrasoc_register_com - register a ultrasoc communicator for communication
+ * between usmsg bus devices and platform bus devices.
+ *
+ * @top_dev: the ultrasoc top platform device to manage all communicator.
+ * @com_descp: the communicator description to be registered.
+ * Return: the pointer to a new communicator if register ok, NULL if failure.
+ */
+struct ultrasoc_com *ultrasoc_register_com(struct device *top_dev,
+					   struct ultrasoc_com_descp *com_descp)
+{
+	struct ultrasoc_drv_data *drv_data = dev_get_drvdata(top_dev);
+	struct ultrasoc_com *com;
+	int ret;
+
+	if (!drv_data)
+		return ERR_PTR(-EBUSY);
+
+	ret = ultrasoc_validate_com_descp(com_descp);
+	if (ret)
+		return ERR_PTR(-EINVAL);
+
+	com = devm_kzalloc(top_dev, sizeof(*com), GFP_KERNEL);
+	if (!com)
+		return ERR_PTR(-ENOMEM);
+
+	com->name = com_descp->name;
+	com->com_type = com_descp->com_type;
+	com->com_ops = com_descp->uscom_ops;
+	com->com_work = com_descp->com_work;
+	com->timeout = US_SERVICE_TIMEOUT;
+	com->core_bind = -1;
+	com->root = top_dev;
+	com->dev = com_descp->com_dev;
+	spin_lock_init(&com->service_lock);
+
+	device_lock(top_dev);
+	list_add_tail(&com->node, &drv_data->ultrasoc_com_head);
+	device_unlock(top_dev);
+
+	if (com->com_type == ULTRASOC_COM_TYPE_BOTH && !drv_data->def_up_com) {
+		/*
+		 * There is one ULTRASOC_COM_TYPE_BOTH device per ultrasoc
+		 * system, so race will not happen.
+		 */
+		drv_data->def_up_com = com;
+		/* start the default communicator service. */
+		com_try_start_service(com);
+		/* set ultrasoc route all msgs to port 1 as default*/
+		com->com_ops->put_raw_msg(com, US_ROUTE_LENGTH,
+					  com_descp->default_route_msg);
+	}
+
+	ret = device_add_groups(com->dev, ultrasoc_com_attr);
+	if (ret)
+		return  ERR_PTR(ret);
+
+	return com;
+}
+EXPORT_SYMBOL_GPL(ultrasoc_register_com);
+
+int ultrasoc_unregister_com(struct ultrasoc_com *com)
+{
+	struct ultrasoc_drv_data *pdata = dev_get_drvdata(com->root);
+	struct device *com_dev = com->dev;
+	struct device *dev = com->root;
+
+	if (wait_com_service_stop(com)) {
+		dev_err(com_dev, "Com service is still running.\n");
+		return -EBUSY;
+	}
+
+	if (pdata->def_up_com == com)
+		pdata->def_up_com = NULL;
+
+	device_lock(dev);
+	list_del(&com->node);
+	device_unlock(dev);
+	device_remove_groups(com_dev, ultrasoc_com_attr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ultrasoc_unregister_com);
+
+MODULE_DESCRIPTION("Ultrasoc driver");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc.h b/drivers/hwtracing/ultrasoc/ultrasoc.h
new file mode 100644
index 0000000..2831e14
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+
+#ifndef _LINUX_ULTRASOC_H
+#define _LINUX_ULTRASOC_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+
+struct ultrasoc_drv_data {
+	struct device *dev;
+	void __iomem *com_mux;
+	struct list_head ultrasoc_com_head;
+	struct ultrasoc_com *def_up_com;
+	const char *dev_data_path;
+	spinlock_t spinlock;
+};
+
+enum ultrasoc_com_type {
+	ULTRASOC_COM_TYPE_BOTH,
+	ULTRASOC_COM_TYPE_DOWN,
+};
+
+struct ultrasoc_com_descp {
+	const char *name;
+	enum ultrasoc_com_type com_type;
+	struct device *com_dev;
+	struct uscom_ops *uscom_ops;
+	int (*com_work)(struct ultrasoc_com *com);
+	u64 default_route_msg;
+};
+
+enum ultrasoc_com_service_status {
+	ULTRASOC_COM_SERVICE_STOPPED,
+	ULTRASOC_COM_SERVICE_SLEEPING,
+	ULTRASOC_COM_SERVICE_RUNNING_NORMAL,
+};
+
+#define USMSG_MAX_IDX				9
+struct msg_descp {
+	unsigned int msg_len;
+	__le32 msg_buf[USMSG_MAX_IDX];
+	struct list_head node;
+};
+
+static inline void usmsg_list_realse_all(struct list_head *msg_head)
+{
+	struct msg_descp *msgd, *next;
+
+	list_for_each_entry_safe(msgd, next, msg_head, node) {
+		list_del(&msgd->node);
+		kfree(msgd);
+	}
+}
+
+struct ultrasoc_com {
+	const char *name;
+	enum ultrasoc_com_type com_type;
+	struct device *root;
+	struct device *dev;
+
+	long core_bind;
+	int (*com_work)(struct ultrasoc_com *com);
+	spinlock_t service_lock;
+	struct task_struct *service;
+	int service_status;
+	unsigned int timeout;
+
+	char *data_path;
+	struct uscom_ops *com_ops;
+
+	struct list_head node;
+};
+
+struct uscom_ops {
+	ssize_t (*com_status)(struct ultrasoc_com *com, char *buf,
+			      ssize_t size);
+	void (*put_raw_msg)(struct ultrasoc_com *com, int msg_size,
+			    unsigned long long msg);
+};
+
+#define uscom_ops_com_status(uscom, buf, size)                           \
+	(((uscom)->com_ops && (uscom)->com_ops->com_status) ?            \
+		 (uscom)->com_ops->com_status(uscom, buf, size) : 0)
+
+static inline void *ultrasoc_com_get_drvdata(struct ultrasoc_com *uscom)
+{
+	return dev_get_drvdata(uscom->dev);
+}
+
+struct ultrasoc_com *
+ultrasoc_register_com(struct device *root_dev,
+		      struct ultrasoc_com_descp *com_descp);
+int ultrasoc_unregister_com(struct ultrasoc_com *com);
+int ultrasoc_com_del_usmsg_device(struct ultrasoc_com *com, int index);
+
+struct ultrasoc_com *ultrasoc_find_com_by_dev(struct device *com_dev);
+
+#define ULTRASOC_COM_ATTR_WO_OPS(attr_name, com_ops)                           \
+	static ssize_t attr_name##_store(struct device *dev,                   \
+					 struct device_attribute *attr,        \
+					 const char *buf, size_t size)         \
+	{                                                                      \
+		struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);      \
+		long attr_name;                                                \
+		int ret;                                                       \
+		if (!com)                                                      \
+			return 0;                                              \
+		ret = kstrtol(buf, 0, &attr_name);                             \
+		if (ret) {                                                     \
+			return size;                                           \
+		}                                                              \
+		if (attr_name == 1) {                                          \
+			com_ops(com);                                          \
+		}                                                              \
+		return size;                                                   \
+	}                                                                      \
+	static DEVICE_ATTR_WO(attr_name)
+
+#define ULTRASOC_COM_ATTR_RO_OPS(attr_name, com_ops)                           \
+	static ssize_t attr_name##_show(struct device *dev,                    \
+					struct device_attribute *attr,         \
+					char *buf)                             \
+	{                                                                      \
+		struct ultrasoc_com *com = ultrasoc_find_com_by_dev(dev);      \
+		if (!com)                                                      \
+			return 0;                                              \
+		return com_ops(com, buf);                                      \
+	}                                                                      \
+	static DEVICE_ATTR_RO(attr_name)
+
+/* 1000 * (10us ~ 100us) */
+#define US_SERVICE_TIMEOUT		1000
+/* communicator service work status */
+#define US_SERVICE_ONWORK		1
+#define US_SERVICE_IDLE			0
+#define US_ROUTE_LENGTH			11
+#define US_SELECT_ONCHIP		0x3
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver
  2021-06-15  9:34 [RFC PATCH 0/4] Add support for Ultrasoc Trace Module Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers Qi Liu
  2021-06-15  9:34 ` [RFC PATCH 2/4] ultrasoc: add ultrasoc core layer framework Qi Liu
@ 2021-06-15  9:34 ` Qi Liu
  2021-06-16 23:23   ` kernel test robot
  2021-06-29 21:22   ` Mathieu Poirier
  2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
  3 siblings, 2 replies; 16+ messages in thread
From: Qi Liu @ 2021-06-15  9:34 UTC (permalink / raw)
  To: alexander.shishkin, mathieu.poirier, suzuki.poulose,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight, linuxarm, liuqi115

This patch adds driver for ultrasoc AXI Communicator. It includes
a platform driver to probe AXI Communicator device, a set of
operations to access the service data, and a service work entry
which will be called by the standard communicator service.

Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
---
 drivers/hwtracing/ultrasoc/Kconfig            |   9 +
 drivers/hwtracing/ultrasoc/Makefile           |   3 +
 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c | 334 ++++++++++++++++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h |  66 +++++
 4 files changed, 412 insertions(+)
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h

diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
index 90a3934..77429f3 100644
--- a/drivers/hwtracing/ultrasoc/Kconfig
+++ b/drivers/hwtracing/ultrasoc/Kconfig
@@ -13,4 +13,13 @@ menuconfig ULTRASOC
 	  specification and configure the right series of components when a
 	  trace source gets enabled.
 
+if ULTRASOC
+config ULTRASOC_AXI_COM
+	tristate "Ultrasoc AXI communicator drivers"
+	help
+	  This config enables support for Ultrasoc AXI Bus Communicator
+	  drivers. The AXI Communicator has upstream and downstream channels,
+	  the upstream channel is used to transmit user configuration, and
+	  downstream channel to carry response and trace data to the users.
+
 endif
diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
index a747171..54711a7b 100644
--- a/drivers/hwtracing/ultrasoc/Makefile
+++ b/drivers/hwtracing/ultrasoc/Makefile
@@ -5,3 +5,6 @@
 
 obj-$(CONFIG_ULTRASOC) += ultrasoc-drv.o
 ultrasoc-drv-objs := ultrasoc.o
+
+obj-$(CONFIG_ULTRASOC_AXI_COM) += ultrasoc-axi-com-drv.o
+ultrasoc-axi-com-drv-objs := ultrasoc-axi-com.o
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
new file mode 100644
index 0000000..af153dd
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+#include <linux/acpi.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/unaligned.h>
+
+#include "ultrasoc-axi-com.h"
+
+static void axi_com_enable_hw(struct axi_com_drv_data *drvdata)
+{
+	u32 val;
+
+	val = readl(drvdata->base + AXIC_US_CTL);
+	val |= AXIC_US_CTL_EN;
+	writel(val, drvdata->base + AXIC_US_CTL);
+
+	val = readl(drvdata->base + AXIC_DS_CTL);
+	val |= AXIC_DS_CTL_EN;
+	writel(val, drvdata->base + AXIC_DS_CTL);
+}
+
+static void axi_com_disable_hw(struct axi_com_drv_data *drvdata)
+{
+	u32 val;
+
+	val = readl(drvdata->base + AXIC_US_CTL);
+	val &= ~AXIC_US_CTL_EN;
+	writel(val, drvdata->base + AXIC_US_CTL);
+
+	val = readl(drvdata->base + AXIC_DS_CTL);
+	val &= ~AXIC_DS_CTL_EN;
+	writel(val, drvdata->base + AXIC_DS_CTL);
+}
+
+static inline bool axi_com_us_buf_full(struct axi_com_drv_data *drvdata)
+{
+	return readl(drvdata->base + AXIC_US_BUF_STS) & BIT(0);
+}
+
+static inline bool axi_com_ds_buf_full(struct axi_com_drv_data *drvdata)
+{
+	return readl(drvdata->base + AXIC_DS_BUF_STS) & BIT(0);
+}
+
+static int axi_com_try_send_msg(struct axi_com_drv_data *drvdata)
+{
+	struct msg_descp *msg;
+	struct list_head *node;
+	int index = 0;
+	int unsent;
+	u32 data;
+
+	if (axi_com_us_buf_full(drvdata)) {
+		dev_err_once(drvdata->dev, "No room for upstream buffer.\n");
+		return US_SERVICE_IDLE;
+	}
+
+	spin_lock(&drvdata->us_msg_list_lock);
+	if (list_empty(&drvdata->us_msg_head)) {
+		spin_unlock(&drvdata->us_msg_list_lock);
+		return US_SERVICE_IDLE;
+	}
+
+	node = drvdata->us_msg_head.next;
+	list_del(node);
+	drvdata->us_msg_cur--;
+	msg = container_of(node, struct msg_descp, node);
+	spin_unlock(&drvdata->us_msg_list_lock);
+
+	unsent = msg->msg_len;
+	dev_dbg(drvdata->dev, "Length of send msg: %d.\n", msg->msg_len);
+	while (unsent > 0) {
+		data = get_unaligned_le32(&msg->msg_buf[index++]);
+		writel(data, drvdata->base + AXIC_US_DATA);
+		unsent -= AXIC_MSG_LEN_PER_SEND;
+	}
+	kfree(msg);
+
+	return US_SERVICE_ONWORK;
+}
+
+static int axi_com_try_recv_msg(struct axi_com_drv_data *drvdata)
+{
+	struct msg_descp tmp_msg = {0};
+	struct msg_descp *msg;
+	bool lost = false;
+	u32 index = 0;
+	u32 status, entries, data;
+
+	if (!axi_com_ds_buf_full(drvdata))
+		return US_SERVICE_IDLE;
+
+	msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+	if (!msg) {
+		/*
+		 * create local variable tmp_msg to read and clear
+		 * the downstream message.
+		 */
+		msg = &tmp_msg;
+		lost = true;
+	}
+
+	do {
+		if (index == USMSG_MAX_IDX) {
+			dev_warn(drvdata->dev, "Illegal message.\n");
+			break;
+		}
+		data = readl(drvdata->base + AXIC_DS_DATA);
+		put_unaligned_le32(data, &msg->msg_buf[index++]);
+		status = readl(drvdata->base + AXIC_DS_RD_STS);
+		entries = status & GENMASK(7, 4);
+		msg->msg_len += AXIC_MSG_LEN_PER_REC;
+	} while (entries != 0);
+
+	if (!lost) {
+		spin_lock(&drvdata->ds_msg_list_lock);
+		drvdata->ds_msg_cur++;
+		drvdata->ds_msg_counter++;
+		list_add_tail(&msg->node, &drvdata->ds_msg_head);
+		spin_unlock(&drvdata->ds_msg_list_lock);
+	}
+
+	return US_SERVICE_ONWORK;
+}
+
+static int axi_com_work(struct ultrasoc_com *uscom)
+{
+	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
+	int us_ds_flag;
+
+	us_ds_flag = axi_com_try_recv_msg(drvdata);
+	us_ds_flag |= axi_com_try_send_msg(drvdata);
+
+	return us_ds_flag;
+}
+
+static ssize_t axi_com_show_status(struct ultrasoc_com *uscom, char *buf,
+				   ssize_t wr_size)
+{
+	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
+
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %d\n",
+				 "ds msg list num", drvdata->ds_msg_cur);
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %d\n",
+				 "us msg list num", drvdata->us_msg_cur);
+
+	return wr_size;
+}
+
+static void axi_com_put_raw_msg(struct ultrasoc_com *uscom, int msg_size,
+			unsigned long long msg_data)
+{
+	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
+	struct msg_descp *p_msg;
+
+	p_msg = kmalloc(sizeof(*p_msg), GFP_KERNEL);
+	if (!p_msg)
+		return;
+
+	p_msg->msg_len = msg_size;
+	put_unaligned_le64(msg_data, &p_msg->msg_buf[0]);
+	spin_lock(&drvdata->us_msg_list_lock);
+	list_add_tail(&p_msg->node, &drvdata->us_msg_head);
+	drvdata->us_msg_cur++;
+	spin_unlock(&drvdata->us_msg_list_lock);
+
+	if (uscom->service_status != ULTRASOC_COM_SERVICE_STOPPED)
+		wake_up_process(uscom->service);
+	else
+		dev_warn(uscom->dev, "Com service is not running.\n");
+}
+
+static struct uscom_ops axi_com_ops = {
+	.com_status = axi_com_show_status,
+	.put_raw_msg = axi_com_put_raw_msg,
+};
+
+/*
+ * Config hardwares on the tracing path, using DSM calls to avoid exposing
+ * hardware message format.
+ */
+static int axi_com_config_inport(struct axi_com_drv_data *drvdata, bool enable)
+{
+	struct device *dev = drvdata->dev;
+	u32 flag = enable ? 1 : 0;
+	union acpi_object *obj;
+	guid_t guid;
+
+	if (guid_parse("82ae1283-7f6a-4cbe-aa06-53e8fb24db18", &guid)) {
+		dev_err(dev, "Get GUID failed.\n");
+		return -EINVAL;
+	}
+
+	obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid, 0, flag, NULL);
+	if (!obj)
+		dev_err(dev, "ACPI handle failed!\n");
+
+	ACPI_FREE(obj);
+
+	return 0;
+}
+
+static int axi_com_config_com_descp(struct platform_device *pdev,
+				    struct axi_com_drv_data *drvdata)
+{
+	struct device *parent = pdev->dev.parent;
+	struct ultrasoc_com_descp com_descp = {0};
+	struct device *dev = &pdev->dev;
+	struct ultrasoc_com *com;
+
+	com_descp.name = pdev->name;
+	com_descp.com_type = ULTRASOC_COM_TYPE_BOTH;
+	com_descp.com_dev = dev;
+	com_descp.uscom_ops = &axi_com_ops;
+	com_descp.com_work = axi_com_work;
+
+	if (device_property_read_u64(dev, "ultrasoc,default_route",
+				     &com_descp.default_route_msg)) {
+		dev_err(dev, "Failed to read default_route!\n");
+		return -EINVAL;
+	}
+
+	com = ultrasoc_register_com(parent, &com_descp);
+	if (IS_ERR(com)) {
+		dev_err(dev, "Failed to register to ultrasoc.\n");
+		return PTR_ERR(com);
+	}
+
+	/*
+	 * record the returned com point in drvdata,
+	 * it will be used to unregister the com
+	 * from ultrasoc.
+	 */
+	drvdata->com = com;
+	return 0;
+}
+
+static int axi_com_probe(struct platform_device *pdev)
+{
+	struct axi_com_drv_data *drvdata;
+	int ret;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(drvdata->base)) {
+		dev_err(&pdev->dev, "Failed to ioremap resource.\n");
+		return PTR_ERR(drvdata->base);
+	}
+
+	drvdata->dev = &pdev->dev;
+	spin_lock_init(&drvdata->ds_msg_list_lock);
+	spin_lock_init(&drvdata->us_msg_list_lock);
+	INIT_LIST_HEAD(&drvdata->us_msg_head);
+	INIT_LIST_HEAD(&drvdata->ds_msg_head);
+
+	axi_com_enable_hw(drvdata);
+	ret = axi_com_config_inport(drvdata, true);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, drvdata);
+	return axi_com_config_com_descp(pdev, drvdata);
+}
+
+static int axi_com_remove(struct platform_device *pdev)
+{
+	struct axi_com_drv_data *drvdata = platform_get_drvdata(pdev);
+	int ret;
+
+	if (ultrasoc_unregister_com(drvdata->com) == -EBUSY)
+		return -EBUSY;
+
+	ret = axi_com_config_inport(drvdata, false);
+	if (ret)
+		return ret;
+
+	axi_com_disable_hw(drvdata);
+	usmsg_list_realse_all(&drvdata->ds_msg_head);
+	usmsg_list_realse_all(&drvdata->us_msg_head);
+
+	return 0;
+}
+
+static const struct acpi_device_id ultrasoc_axi_com_acpi_match[] = {
+	{"HISI03B1", },
+	{},
+};
+
+static struct platform_driver axi_com_driver = {
+	.driver = {
+		.name = "ultrasoc,axi-com",
+		.acpi_match_table = ultrasoc_axi_com_acpi_match,
+	},
+	.probe = axi_com_probe,
+	.remove = axi_com_remove,
+};
+module_platform_driver(axi_com_driver);
+
+MODULE_DESCRIPTION("Ultrasoc AXI COM driver");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
new file mode 100644
index 0000000..64bcf83
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+#ifndef ULTRASOC_AXI_COM_H
+#define ULTRASOC_AXI_COM_H
+
+#include "ultrasoc.h"
+
+#define AXIC_US_CTL 0X0 /* Upstream general control */
+#define AXIC_US_DATA 0XC /* Upstream message data */
+#define AXIC_US_BUF_STS 0X10 /* Upstream buffer status */
+
+#define AXIC_DS_CTL 0X80 /* Downstream general contral */
+#define AXIC_DS_DATA 0X8C /* Downstream message data */
+#define AXIC_DS_BUF_STS 0X90 /* Downstream buffer status */
+#define AXIC_DS_RD_STS 0X94 /* Downstream read status */
+
+#define AXIC_MSG_LEN_PER_SEND		4
+#define AXIC_MSG_LEN_PER_REC		4
+#define AXIC_US_CTL_EN 0x1
+#define AXIC_DS_CTL_EN 0x1
+
+struct axi_com_drv_data {
+	void __iomem *base;
+
+	struct device *dev;
+	struct ultrasoc_com *com;
+
+	u32 ds_msg_counter;
+
+	u32 us_msg_cur;
+	spinlock_t us_msg_list_lock;
+	struct list_head us_msg_head;
+
+	u32 ds_msg_cur;
+	spinlock_t ds_msg_list_lock;
+	struct list_head ds_msg_head;
+};
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-15  9:34 [RFC PATCH 0/4] Add support for Ultrasoc Trace Module Qi Liu
                   ` (2 preceding siblings ...)
  2021-06-15  9:34 ` [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver Qi Liu
@ 2021-06-15  9:34 ` Qi Liu
  2021-06-16 18:04   ` kernel test robot
                     ` (2 more replies)
  3 siblings, 3 replies; 16+ messages in thread
From: Qi Liu @ 2021-06-15  9:34 UTC (permalink / raw)
  To: alexander.shishkin, mathieu.poirier, suzuki.poulose,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight, linuxarm, liuqi115

This patch adds driver for System Memory Buffer. It includes
a platform driver for the SMB device.

Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
Signed-off-by: Qi Liu <liuqi115@huawei.com>
---
 drivers/hwtracing/ultrasoc/Kconfig        |   9 +
 drivers/hwtracing/ultrasoc/Makefile       |   3 +
 drivers/hwtracing/ultrasoc/ultrasoc-smb.c | 663 ++++++++++++++++++++++++++++++
 drivers/hwtracing/ultrasoc/ultrasoc-smb.h | 182 ++++++++
 4 files changed, 857 insertions(+)
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
 create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h

diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
index 77429f3..8899949 100644
--- a/drivers/hwtracing/ultrasoc/Kconfig
+++ b/drivers/hwtracing/ultrasoc/Kconfig
@@ -22,4 +22,13 @@ config ULTRASOC_AXI_COM
 	  the upstream channel is used to transmit user configuration, and
 	  downstream channel to carry response and trace data to the users.
 
+config ULTRASOC_SMB
+	tristate "Ultrasoc System memory buffer drivers"
+	help
+	  This config enables support for Ultrasoc System Memory Buffer
+	  drivers. The System Memory Buffer provides a way to buffer and
+	  store messages in system memory. It provides a capability to
+	  store messages received on its input message interface to an
+	  area of system memory.
+
 endif
diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
index 54711a7b..b174ca8 100644
--- a/drivers/hwtracing/ultrasoc/Makefile
+++ b/drivers/hwtracing/ultrasoc/Makefile
@@ -8,3 +8,6 @@ ultrasoc-drv-objs := ultrasoc.o
 
 obj-$(CONFIG_ULTRASOC_AXI_COM) += ultrasoc-axi-com-drv.o
 ultrasoc-axi-com-drv-objs := ultrasoc-axi-com.o
+
+obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb-drv.o
+ultrasoc-smb-drv-objs := ultrasoc-smb.o
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-smb.c b/drivers/hwtracing/ultrasoc/ultrasoc-smb.c
new file mode 100644
index 0000000..ce03f5e
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc-smb.c
@@ -0,0 +1,663 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+
+#include <linux/circ_buf.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "ultrasoc-smb.h"
+
+static inline int smb_hw_buffer_empty(struct smb_drv_data *drvdata)
+{
+	u32 buf_status = readl(drvdata->base + SMB_LB_INT_STS);
+
+	return buf_status & BIT(0) ? 0 : 1;
+}
+
+static inline int smb_buffer_pointer_pos(struct smb_drv_data *drvdata)
+{
+	u32 wr_offset, rd_offset;
+
+	wr_offset = readl(drvdata->base + SMB_LB_WR_ADDR);
+	rd_offset = readl(drvdata->base + SMB_LB_RD_ADDR);
+	return wr_offset == rd_offset;
+}
+
+static inline int smb_hw_buffer_full(struct smb_drv_data *drvdata)
+{
+	return smb_buffer_pointer_pos(drvdata) && !smb_hw_buffer_empty(drvdata);
+}
+
+static inline void smb_clear_buf_status(struct smb_drv_data *drvdata)
+{
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+
+	if (smb_buffer_pointer_pos(drvdata) && !sdb->to_copy)
+		writel(0xf, drvdata->base + SMB_LB_INT_STS);
+}
+
+static void smb_update_hw_write_size(struct smb_drv_data *drvdata)
+{
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+	u32 write_offset, write_base;
+
+	sdb->lost = false;
+	writel(0x1, drvdata->base + SMB_LB_PURGE);
+	if (smb_hw_buffer_empty(drvdata)) {
+		sdb->to_copy = 0;
+		return;
+	}
+
+	if (smb_hw_buffer_full(drvdata)) {
+		sdb->to_copy = sdb->buf_size;
+		return;
+	}
+
+	write_base = sdb->buf_base_phys & SMB_BUF_WRITE_BASE;
+	write_offset = readl(drvdata->base + SMB_LB_WR_ADDR) - write_base;
+	sdb->to_copy = CIRC_CNT(write_offset, sdb->rd_offset, sdb->buf_size);
+}
+
+static int smb_open(struct inode *inode, struct file *file)
+{
+	struct smb_drv_data *drvdata = container_of(file->private_data,
+			struct smb_drv_data, miscdev);
+
+	if (local_cmpxchg(&drvdata->reading, 0, 1))
+		return -EBUSY;
+
+	smb_update_hw_write_size(drvdata);
+	return 0;
+}
+
+static ssize_t smb_read(struct file *file, char __user *data,
+			size_t len, loff_t *ppos)
+{
+	struct smb_drv_data *drvdata = container_of(file->private_data,
+			struct smb_drv_data, miscdev);
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+	struct device *dev = &drvdata->csdev->dev;
+	unsigned long to_copy = sdb->to_copy;
+
+	if (!to_copy) {
+		smb_update_hw_write_size(drvdata);
+		to_copy = sdb->to_copy;
+		if (!to_copy)
+			return to_copy;
+	}
+
+	to_copy = min(to_copy, len);
+	/*
+	 * if the read needs to cross the boundary of the data buffer, copy
+	 * last datas of the buffer to user
+	 */
+	if (sdb->rd_offset + to_copy > sdb->buf_size)
+		to_copy = sdb->buf_size - sdb->rd_offset;
+
+	if (copy_to_user(data, (void *)sdb->buf_base + sdb->rd_offset, to_copy)) {
+		dev_dbg(dev, "Failed to copy data to user.\n");
+		return -EFAULT;
+	}
+
+	*ppos += to_copy;
+	sdb->rd_offset += to_copy;
+	sdb->rd_offset %= sdb->buf_size;
+	sdb->to_copy -= to_copy;
+
+	/* update the read point */
+	writel(sdb->buf_base_phys + sdb->rd_offset,
+	       drvdata->base + SMB_LB_RD_ADDR);
+	smb_clear_buf_status(drvdata);
+	dev_dbg(dev, "%lu bytes copied.\n", to_copy);
+
+	return to_copy;
+}
+
+static int smb_release(struct inode *inode, struct file *file)
+{
+	struct smb_drv_data *drvdata = container_of(file->private_data,
+			struct smb_drv_data, miscdev);
+	local_set(&drvdata->reading, 0);
+	return 0;
+}
+
+static const struct file_operations smb_fops = {
+	.owner		= THIS_MODULE,
+	.open		= smb_open,
+	.read		= smb_read,
+	.release	= smb_release,
+	.llseek		= no_llseek,
+};
+
+static ssize_t smb_show_status(struct ultrasoc_com *com, char *buf,
+			       ssize_t wr_size)
+{
+	struct smb_drv_data *drvdata;
+	u32 value;
+
+	drvdata = dev_get_drvdata(com->dev);
+	value = readl(drvdata->base + SMB_LB_INT_STS);
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: 0x%08x\n",
+				 "interrupt status", value);
+	value = readl(drvdata->base + SMB_LB_WR_ADDR);
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "write point",
+				 value);
+	value = readl(drvdata->base + SMB_LB_RD_ADDR);
+	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "read point",
+				 value);
+
+	return wr_size;
+}
+
+static int smb_init_data_buffer(struct platform_device *pdev,
+				struct smb_data_buffer *sdb)
+{
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (IS_ERR(res)) {
+		dev_err(&pdev->dev, "SMB device without data buffer.\n");
+		return -EINVAL;
+	}
+
+	sdb->buf_base_phys = res->start;
+	sdb->buf_size = resource_size(res);
+	if (sdb->buf_size == 0)
+		return -EINVAL;
+
+	sdb->buf_base = ioremap_cache(sdb->buf_base_phys, sdb->buf_size);
+	if (sdb->buf_base == NULL)
+		return -ENOMEM;
+
+	sdb->buf_cfg_mode = SMB_BUF_CFG_STREAMING;
+	return 0;
+}
+
+static void smb_release_data_buffer(struct smb_drv_data *drvdata)
+{
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+
+	if (sdb->buf_base)
+		iounmap(sdb->buf_base);
+}
+
+static struct uscom_ops smb_ops = {
+	.com_status = smb_show_status,
+	.put_raw_msg = NULL,
+};
+
+static int smb_set_buffer(struct coresight_device *csdev,
+		struct perf_output_handle *handle);
+
+static void smb_enable_hw(struct smb_drv_data *drvdata)
+{
+	writel(0x1, drvdata->base + SMB_GLOBAL_EN);
+}
+
+static void smb_disable_hw(struct smb_drv_data *drvdata)
+{
+	writel(0x1, drvdata->base + SMB_LB_PURGE);
+	writel(0x0, drvdata->base + SMB_GLOBAL_EN);
+}
+
+static int smb_enable_sysfs(struct coresight_device *csdev)
+{
+	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+	int ret = 0;
+
+	WARN_ON_ONCE(drvdata == NULL);
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	/* Don't messup with perf sessions. */
+	if (drvdata->mode == CS_MODE_PERF) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	if (drvdata->mode == CS_MODE_DISABLED) {
+		smb_enable_hw(drvdata);
+		drvdata->mode = CS_MODE_SYSFS;
+	}
+	atomic_inc(csdev->refcnt);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	return ret;
+}
+
+static int smb_enable_perf(struct coresight_device *csdev, void *data)
+{
+	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct device *dev = &drvdata->csdev->dev;
+	struct perf_output_handle *handle = data;
+	unsigned long flags;
+	int ret = 0;
+	pid_t pid;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+	if (drvdata->mode == CS_MODE_SYSFS) {
+		dev_err(dev, "Device is already in used by sysfs.\n");
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/* Get a handle on the pid of the target process*/
+	pid = task_pid_nr(handle->event->owner);
+	if (drvdata->pid != -1 && drvdata->pid != pid) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/*
+	 * No HW configuration is needed if the sink is already in
+	 * use for this session.
+	 */
+	if (drvdata->pid == pid) {
+		atomic_inc(csdev->refcnt);
+		goto out;
+	}
+
+	/*
+	 * We don't have an internal state to clean up if we fail to setup
+	 * the perf buffer. So we can perform the step before we turn the
+	 * ETB on and leave without cleaning up.
+	 */
+	ret = smb_set_buffer(csdev, handle);
+	if (ret)
+		goto out;
+
+	smb_enable_hw(drvdata);
+	drvdata->pid = pid;
+	drvdata->mode = CS_MODE_PERF;
+	atomic_inc(csdev->refcnt);
+out:
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+	return ret;
+}
+
+static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
+{
+	int ret;
+
+	switch (mode) {
+	case CS_MODE_SYSFS:
+		ret = smb_enable_sysfs(csdev);
+		break;
+	case CS_MODE_PERF:
+		ret = smb_enable_perf(csdev, data);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	dev_dbg(&csdev->dev, "Ultrasoc smb enabled.\n");
+
+	return 0;
+}
+
+static int smb_disable(struct coresight_device *csdev)
+{
+	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(&drvdata->spinlock, flags);
+
+	if (atomic_dec_return(csdev->refcnt)) {
+		spin_unlock_irqrestore(&drvdata->spinlock, flags);
+		return -EBUSY;
+	}
+
+	/* Complain if we (somehow) got out of sync */
+	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
+	smb_disable_hw(drvdata);
+
+	/* Dissociate from the target process. */
+	drvdata->pid = -1;
+	drvdata->mode = CS_MODE_DISABLED;
+	spin_unlock_irqrestore(&drvdata->spinlock, flags);
+
+	dev_dbg(&csdev->dev, "Ultrasoc smb disabled.\n");
+	return 0;
+}
+
+static void smb_set_default_hw(struct smb_drv_data *drvdata)
+{
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+	u32 value, base_hi, base_lo, limit_lo;
+
+	/* first disable smb and clear the status of SMB buffer */
+	smb_disable_hw(drvdata);
+	smb_clear_buf_status(drvdata);
+
+	/* using smb in single-end mode, and set other configures default */
+	value = sdb->buf_cfg_mode | SMB_BUF_SINGLE_END | SMB_BUF_ENABLE;
+	writel(value, drvdata->base + SMB_LB_CFG_LO);
+	value = SMB_MSG_FILTER(0x0, 0xff);
+	writel(value, drvdata->base + SMB_LB_CFG_HI);
+
+	writel(HISI_SMB_GLOBAL_CFG, drvdata->base + SMB_GLOBAL_CFG);
+	writel(HISI_SMB_GLB_INT_CFG, drvdata->base + SMB_GLOBAL_INT);
+	writel(HISI_SMB_BUF_INT_CFG, drvdata->base + SMB_LB_INT_CTRL);
+
+	/* config hardware registers according to physical base of SMB buffer */
+	base_hi = sdb->buf_base_phys >> 32;
+	base_lo = sdb->buf_base_phys & SMB_BUF_WRITE_BASE;
+	limit_lo = base_lo + sdb->buf_size;
+	writel(base_lo, drvdata->base + SMB_LB_BASE_LO);
+	writel(base_hi, drvdata->base + SMB_LB_BASE_HI);
+	writel(limit_lo, drvdata->base + SMB_LB_LIMIT);
+
+	/* initial hardware read-ptr address*/
+	writel(base_lo, drvdata->base + SMB_LB_RD_ADDR);
+}
+
+static void *smb_alloc_buffer(struct coresight_device *csdev,
+		struct perf_event *event, void **pages,
+		int nr_pages, bool overwrite)
+{
+	struct cs_buffers *buf;
+	int node;
+
+	node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
+	buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
+	if (!buf)
+		return NULL;
+
+	buf->snapshot = overwrite;
+	buf->nr_pages = nr_pages;
+	buf->data_pages = pages;
+
+	return buf;
+}
+
+static void smb_free_buffer(void *config)
+{
+	struct cs_buffers *buf = config;
+
+	kfree(buf);
+}
+
+static int smb_set_buffer(struct coresight_device *csdev,
+		struct perf_output_handle *handle)
+{
+	struct cs_buffers *buf = etm_perf_sink_config(handle);
+	u32 head;
+
+	if (!buf)
+		return -EINVAL;
+
+	/* wrap head around to the amount of space we have */
+	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
+
+	/* find the page to write to and offset within that page */
+	buf->cur = head / PAGE_SIZE;
+	buf->offset = head % PAGE_SIZE;
+
+	local_set(&buf->data_size, 0);
+
+	return 0;
+}
+
+static void smb_sync_perf_buffer(struct smb_drv_data *drvdata,
+				 struct cs_buffers *buf, unsigned long to_copy)
+{
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+	char **dst_pages = (char **)buf->data_pages;
+	u32 buf_offset = buf->offset;
+	u32 cur = buf->cur;
+	u32 bytes;
+
+	while (to_copy > 0) {
+		/*
+		 * if the read needs to cross the boundary of the data buffer,
+		 * copy last datas of the buffer to user
+		 */
+		if (sdb->rd_offset + PAGE_SIZE - buf_offset > sdb->buf_size)
+			bytes = sdb->buf_size - sdb->rd_offset;
+		else
+			bytes = min(to_copy, PAGE_SIZE - buf_offset);
+
+		memcpy_fromio(dst_pages[cur] + buf_offset,
+		       sdb->buf_base + sdb->rd_offset, bytes);
+
+		buf_offset += bytes;
+		if (buf_offset >= PAGE_SIZE) {
+			buf_offset = 0;
+			cur++;
+			cur %= buf->nr_pages;
+		}
+		to_copy -= bytes;
+		/* ensure memcpy finished before update the read pointer */
+		sdb->rd_offset += bytes;
+		sdb->rd_offset %= sdb->buf_size;
+	}
+
+	writel(sdb->buf_base_phys + sdb->rd_offset,
+	       drvdata->base + SMB_LB_RD_ADDR);
+	sdb->to_copy = to_copy;
+}
+
+static unsigned long smb_update_buffer(struct coresight_device *csdev,
+		struct perf_output_handle *handle, void *sink_config)
+{
+	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
+	struct smb_data_buffer *sdb = &drvdata->smb_db;
+	struct cs_buffers *buf = sink_config;
+	u64 to_copy;
+
+	if (!buf)
+		return 0;
+
+	smb_update_hw_write_size(drvdata);
+	to_copy = sdb->to_copy;
+	if (to_copy > handle->size) {
+		sdb->rd_offset += (to_copy - handle->size);
+		sdb->rd_offset %= sdb->buf_size;
+		to_copy = handle->size;
+		sdb->lost = true;
+	}
+
+	smb_sync_perf_buffer(drvdata, buf, to_copy);
+	smb_clear_buf_status(drvdata);
+	if (!buf->snapshot && sdb->lost)
+		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
+
+	return to_copy;
+}
+
+static const struct coresight_ops_sink smb_cs_ops = {
+	.enable		= smb_enable,
+	.disable	= smb_disable,
+	.alloc_buffer	= smb_alloc_buffer,
+	.free_buffer	= smb_free_buffer,
+	.update_buffer	= smb_update_buffer,
+};
+
+static const struct coresight_ops cs_ops = {
+	.sink_ops	= &smb_cs_ops,
+};
+
+static int smb_init_res(struct platform_device *pdev,
+			struct smb_drv_data *drvdata)
+{
+	struct smb_data_buffer *sdb;
+	int ret;
+
+	sdb = &drvdata->smb_db;
+	drvdata->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(drvdata->base)) {
+		dev_err(&pdev->dev, "Failed to ioremap resource.\n");
+		return PTR_ERR(drvdata->base);
+	}
+
+	ret = smb_init_data_buffer(pdev, sdb);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to init buffer, ret = %d.\n", ret);
+
+	return ret;
+}
+
+DEFINE_CORESIGHT_DEVLIST(sink_devs, "sink_smb");
+static int smb_register_sink(struct platform_device *pdev,
+			     struct smb_drv_data *drvdata)
+{
+	struct coresight_platform_data *pdata = NULL;
+	struct coresight_desc desc = { 0 };
+	int ret;
+
+	pdata = coresight_get_platform_data(&pdev->dev);
+	if (IS_ERR(pdata))
+		return PTR_ERR(pdata);
+
+	drvdata->dev->platform_data = pdata;
+	desc.type = CORESIGHT_DEV_TYPE_SINK;
+	desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+	desc.ops = &cs_ops;
+	desc.pdata = pdata;
+	desc.dev = &pdev->dev;
+	desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
+	if (!desc.name) {
+		dev_err(&pdev->dev, "Failed to alloc coresight device name.");
+		return -ENOMEM;
+	}
+
+	drvdata->csdev = coresight_register(&desc);
+	if (IS_ERR(drvdata->csdev))
+		return PTR_ERR(drvdata->csdev);
+
+	drvdata->miscdev.name = desc.name;
+	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
+	drvdata->miscdev.fops = &smb_fops;
+	ret = misc_register(&drvdata->miscdev);
+	if (ret) {
+		coresight_unregister(drvdata->csdev);
+		dev_err(&pdev->dev, "Failed to register misc, ret=%d\n", ret);
+	}
+
+	return ret;
+}
+
+static void smb_unregister_sink(struct smb_drv_data *drvdata)
+{
+	misc_deregister(&drvdata->miscdev);
+	coresight_unregister(drvdata->csdev);
+}
+
+static int smb_config_com_descp(struct platform_device *pdev,
+				struct smb_drv_data *drvdata)
+{
+	struct device *parent = pdev->dev.parent;
+	struct ultrasoc_com_descp com_descp = {0};
+	struct device *dev = &pdev->dev;
+	struct ultrasoc_com *com;
+
+	com_descp.name = pdev->name;
+	com_descp.com_type = ULTRASOC_COM_TYPE_DOWN;
+	com_descp.com_dev = dev;
+	com_descp.uscom_ops = &smb_ops;
+	com = ultrasoc_register_com(parent, &com_descp);
+	if (IS_ERR(com)) {
+		dev_err(dev, "Failed to register smb com.\n");
+		return PTR_ERR(com);
+	}
+
+	drvdata->com = com;
+	return 0;
+}
+
+static int smb_probe(struct platform_device *pdev)
+{
+	struct smb_drv_data *drvdata;
+	int ret;
+
+	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata)
+		return -ENOMEM;
+
+	ret = smb_init_res(pdev, drvdata);
+	if (ret)
+		return ret;
+
+	smb_set_default_hw(drvdata);
+	spin_lock_init(&drvdata->spinlock);
+	drvdata->dev = &pdev->dev;
+	drvdata->pid = -1;
+
+	ret = smb_config_com_descp(pdev, drvdata);
+	if (ret)
+		return ret;
+
+	ret = smb_register_sink(pdev, drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register smb sink.\n");
+		ultrasoc_unregister_com(drvdata->com);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, drvdata);
+	return 0;
+}
+
+static int smb_remove(struct platform_device *pdev)
+{
+	struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
+
+	smb_unregister_sink(drvdata);
+	ultrasoc_unregister_com(drvdata->com);
+	smb_release_data_buffer(drvdata);
+	return 0;
+}
+
+static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
+	{"HISI03A1", },
+	{},
+};
+
+static struct platform_driver smb_driver = {
+	.driver = {
+		.name = "ultrasoc,smb",
+		.acpi_match_table = ultrasoc_smb_acpi_match,
+	},
+	.probe = smb_probe,
+	.remove = smb_remove,
+};
+module_platform_driver(smb_driver);
+
+MODULE_DESCRIPTION("Ultrasoc smb driver");
+MODULE_LICENSE("Dual MIT/GPL");
+MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
+MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-smb.h b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
new file mode 100644
index 0000000..e37d510
--- /dev/null
+++ b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Code herein communicates with and accesses proprietary hardware which is
+ * licensed intellectual property (IP) belonging to Siemens Digital Industries
+ * Software Ltd.
+ *
+ * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
+ * their intellectual property. This paragraph may not be removed or modified
+ * in any way without permission from Siemens Digital Industries Software Ltd.
+ */
+
+#ifndef _ULTRASOC_SMB_H
+#define _ULTRASOC_SMB_H
+
+#include <linux/coresight.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+
+#include "ultrasoc.h"
+
+#define SMB_GLOBAL_CFG		0X0
+#define SMB_GLOBAL_EN		0X4
+#define SMB_GLOBAL_INT		0X8
+#define SMB_LB_CFG_LO		0X40
+#define SMB_LB_CFG_HI		0X44
+#define SMB_LB_INT_CTRL		0X48
+#define SMB_LB_INT_STS		0X4C
+#define SMB_LB_BASE_LO		0X50
+#define SMB_LB_BASE_HI		0X54
+#define SMB_LB_LIMIT		0X58
+#define SMB_LB_RD_ADDR		0X5C
+#define SMB_LB_WR_ADDR		0X60
+#define SMB_LB_PURGE		0X64
+
+#define SMB_MSG_LC(lc)		((lc & 0x3) << 2)
+#define SMB_BST_LEN(len)	(((len - 1) & 0xff) << 4)
+/* idle message injection timer period */
+#define SMB_IDLE_PRD(period)	(((period - 216) & 0xf) << 12)
+#define SMB_MEM_WR(credit, rate) (((credit & 0x3) << 16) | ((rate & 0xf) << 18))
+#define SMB_MEM_RD(credit, rate) (((credit & 0x3) << 22) | ((rate & 0xf) << 24))
+#define HISI_SMB_GLOBAL_CFG                                                    \
+	(SMB_MSG_LC(0) | SMB_IDLE_PRD(231) | SMB_MEM_WR(0x3, 0x0) |            \
+	 SMB_MEM_RD(0x3, 0x6) | SMB_BST_LEN(16))
+
+#define SMB_INT_ENABLE		BIT(0)
+#define SMB_INT_TYPE_PULSE	BIT(1)
+#define SMB_INT_POLARITY_HIGH	BIT(2)
+#define HISI_SMB_GLB_INT_CFG	(SMB_INT_ENABLE | SMB_INT_TYPE_PULSE |         \
+				SMB_INT_POLARITY_HIGH)
+
+/* logic buffer config register low 32b */
+#define SMB_BUF_ENABLE			BIT(0)
+#define SMB_BUF_SINGLE_END		BIT(1)
+#define SMB_BUF_INIT			BIT(8)
+#define SMB_BUF_CONTINUOUS		BIT(11)
+#define SMB_FLOW_MASK			GENMASK(19, 16)
+#define SMB_BUF_CFG_STREAMING						       \
+	(SMB_BUF_INIT | SMB_BUF_CONTINUOUS | SMB_FLOW_MASK)
+#define SMB_BUF_WRITE_BASE		GENMASK(31, 0)
+
+/* logic buffer config register high 32b */
+#define SMB_MSG_FILTER(lower, upper)	((lower & 0xff) | ((upper & 0xff) << 8))
+#define SMB_BUF_INT_ENABLE		BIT(0)
+#define SMB_BUF_NOTE_NOT_EMPTY		BIT(8)
+#define SMB_BUF_NOTE_BLOCK_AVAIL	BIT(9)
+#define SMB_BUF_NOTE_TRIGGERED		BIT(10)
+#define SMB_BUF_NOTE_FULL		BIT(11)
+#define HISI_SMB_BUF_INT_CFG						\
+	(SMB_BUF_INT_ENABLE | SMB_BUF_NOTE_NOT_EMPTY |			\
+	   SMB_BUF_NOTE_BLOCK_AVAIL | SMB_BUF_NOTE_TRIGGERED |		\
+	    SMB_BUF_NOTE_FULL)
+
+struct smb_data_buffer {
+	/* memory buffer for hardware write */
+	u32 buf_cfg_mode;
+	bool lost;
+	void __iomem *buf_base;
+	u64 buf_base_phys;
+	u64 buf_size;
+	u64 to_copy;
+	u32 rd_offset;
+};
+
+struct smb_drv_data {
+	void __iomem *base;
+	struct device *dev;
+	struct ultrasoc_com *com;
+	struct smb_data_buffer smb_db;
+	/* to register ultrasoc smb as a coresight sink device. */
+	struct coresight_device	*csdev;
+	spinlock_t		spinlock;
+	local_t			reading;
+	pid_t			pid;
+	u32			mode;
+	struct miscdevice miscdev;
+};
+
+#define SMB_MSG_ALIGH_SIZE 0x400
+
+static inline struct smb_data_buffer *
+	dev_get_smb_data_buffer(struct device *dev)
+{
+	struct smb_drv_data *drvdata = dev_get_drvdata(dev);
+
+	if (drvdata)
+		return &drvdata->smb_db;
+
+	return NULL;
+}
+
+/*
+ * Coresight doesn't export the following
+ * structures(cs_mode,cs_buffers,etm_event_data),
+ * so we redefine a copy here.
+ */
+enum cs_mode {
+	CS_MODE_DISABLED,
+	CS_MODE_SYSFS,
+	CS_MODE_PERF,
+};
+
+struct cs_buffers {
+	unsigned int		cur;
+	unsigned int		nr_pages;
+	unsigned long		offset;
+	local_t			data_size;
+	bool			snapshot;
+	void			**data_pages;
+};
+
+struct etm_event_data {
+	struct work_struct work;
+	cpumask_t mask;
+	void *snk_config;
+	struct list_head * __percpu *path;
+};
+
+#if IS_ENABLED(CONFIG_CORESIGHT)
+int etm_perf_symlink(struct coresight_device *csdev, bool link);
+int etm_perf_add_symlink_sink(struct coresight_device *csdev);
+void etm_perf_del_symlink_sink(struct coresight_device *csdev);
+static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
+{
+	struct etm_event_data *data = perf_get_aux(handle);
+
+	if (data)
+		return data->snk_config;
+	return NULL;
+}
+#else
+static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
+{ return -EINVAL; }
+int etm_perf_add_symlink_sink(struct coresight_device *csdev)
+{ return -EINVAL; }
+void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
+static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
+{
+	return NULL;
+}
+
+#endif /* CONFIG_CORESIGHT */
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
@ 2021-06-16 18:04   ` kernel test robot
  2021-06-24 22:47   ` Suzuki K Poulose
  2021-06-29 20:50   ` Mathieu Poirier
  2 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2021-06-16 18:04 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 4268 bytes --]

Hi Qi,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on linus/master]
[also build test ERROR on v5.13-rc6 next-20210616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Qi-Liu/Add-support-for-Ultrasoc-Trace-Module/20210616-151905
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94f0b2d4a1d0c52035aef425da5e022bd2cb1c71
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/b5544dc3a2731c7be00b04a0d497f892d56fc6aa
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Qi-Liu/Add-support-for-Ultrasoc-Trace-Module/20210616-151905
        git checkout b5544dc3a2731c7be00b04a0d497f892d56fc6aa
        # save the attached .config to linux build tree
        make W=1 ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from drivers/hwtracing/ultrasoc/ultrasoc-smb.c:37:
   drivers/hwtracing/ultrasoc/ultrasoc-smb.h:172:5: warning: no previous prototype for 'etm_perf_add_symlink_sink' [-Wmissing-prototypes]
     172 | int etm_perf_add_symlink_sink(struct coresight_device *csdev)
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-smb.h:174:6: warning: no previous prototype for 'etm_perf_del_symlink_sink' [-Wmissing-prototypes]
     174 | void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
         |      ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-smb.c: In function 'smb_register_sink':
>> drivers/hwtracing/ultrasoc/ultrasoc-smb.c:552:14: error: implicit declaration of function 'coresight_alloc_device_name'; did you mean 'coresight_claim_device'? [-Werror=implicit-function-declaration]
     552 |  desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
         |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~
         |              coresight_claim_device
   drivers/hwtracing/ultrasoc/ultrasoc-smb.c:552:12: warning: assignment to 'const char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
     552 |  desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
         |            ^
   cc1: some warnings being treated as errors


vim +552 drivers/hwtracing/ultrasoc/ultrasoc-smb.c

   533	
   534	DEFINE_CORESIGHT_DEVLIST(sink_devs, "sink_smb");
   535	static int smb_register_sink(struct platform_device *pdev,
   536				     struct smb_drv_data *drvdata)
   537	{
   538		struct coresight_platform_data *pdata = NULL;
   539		struct coresight_desc desc = { 0 };
   540		int ret;
   541	
   542		pdata = coresight_get_platform_data(&pdev->dev);
   543		if (IS_ERR(pdata))
   544			return PTR_ERR(pdata);
   545	
   546		drvdata->dev->platform_data = pdata;
   547		desc.type = CORESIGHT_DEV_TYPE_SINK;
   548		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
   549		desc.ops = &cs_ops;
   550		desc.pdata = pdata;
   551		desc.dev = &pdev->dev;
 > 552		desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
   553		if (!desc.name) {
   554			dev_err(&pdev->dev, "Failed to alloc coresight device name.");
   555			return -ENOMEM;
   556		}
   557	
   558		drvdata->csdev = coresight_register(&desc);
   559		if (IS_ERR(drvdata->csdev))
   560			return PTR_ERR(drvdata->csdev);
   561	
   562		drvdata->miscdev.name = desc.name;
   563		drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
   564		drvdata->miscdev.fops = &smb_fops;
   565		ret = misc_register(&drvdata->miscdev);
   566		if (ret) {
   567			coresight_unregister(drvdata->csdev);
   568			dev_err(&pdev->dev, "Failed to register misc, ret=%d\n", ret);
   569		}
   570	
   571		return ret;
   572	}
   573	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 65679 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver
  2021-06-15  9:34 ` [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver Qi Liu
@ 2021-06-16 23:23   ` kernel test robot
  2021-06-29 21:22   ` Mathieu Poirier
  1 sibling, 0 replies; 16+ messages in thread
From: kernel test robot @ 2021-06-16 23:23 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 7949 bytes --]

Hi Qi,

[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on linus/master]
[also build test ERROR on v5.13-rc6 next-20210616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Qi-Liu/Add-support-for-Ultrasoc-Trace-Module/20210616-151905
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94f0b2d4a1d0c52035aef425da5e022bd2cb1c71
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/34aa8589f94ed20eca533ed8463184bb3194f80d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Qi-Liu/Add-support-for-Ultrasoc-Trace-Module/20210616-151905
        git checkout 34aa8589f94ed20eca533ed8463184bb3194f80d
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c: In function 'axi_com_enable_hw':
>> drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:42:8: error: implicit declaration of function 'readl' [-Werror=implicit-function-declaration]
      42 |  val = readl(drvdata->base + AXIC_US_CTL);
         |        ^~~~~
>> drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:44:2: error: implicit declaration of function 'writel' [-Werror=implicit-function-declaration]
      44 |  writel(val, drvdata->base + AXIC_US_CTL);
         |  ^~~~~~
   In file included from include/linux/device.h:32,
                    from include/linux/acpi.h:15,
                    from drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:30:
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c: At top level:
>> include/linux/device/driver.h:263:1: warning: data definition has no type or storage class
     263 | module_init(__driver##_init); \
         | ^~~~~~~~~~~
   include/linux/platform_device.h:257:2: note: in expansion of macro 'module_driver'
     257 |  module_driver(__platform_driver, platform_driver_register, \
         |  ^~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
>> include/linux/device/driver.h:263:1: error: type defaults to 'int' in declaration of 'module_init' [-Werror=implicit-int]
     263 | module_init(__driver##_init); \
         | ^~~~~~~~~~~
   include/linux/platform_device.h:257:2: note: in expansion of macro 'module_driver'
     257 |  module_driver(__platform_driver, platform_driver_register, \
         |  ^~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: warning: parameter names (without types) in function declaration
   In file included from include/linux/device.h:32,
                    from include/linux/acpi.h:15,
                    from drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:30:
   include/linux/device/driver.h:268:1: warning: data definition has no type or storage class
     268 | module_exit(__driver##_exit);
         | ^~~~~~~~~~~
   include/linux/platform_device.h:257:2: note: in expansion of macro 'module_driver'
     257 |  module_driver(__platform_driver, platform_driver_register, \
         |  ^~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
>> include/linux/device/driver.h:268:1: error: type defaults to 'int' in declaration of 'module_exit' [-Werror=implicit-int]
     268 | module_exit(__driver##_exit);
         | ^~~~~~~~~~~
   include/linux/platform_device.h:257:2: note: in expansion of macro 'module_driver'
     257 |  module_driver(__platform_driver, platform_driver_register, \
         |  ^~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
>> drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: warning: parameter names (without types) in function declaration
>> drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:331:20: error: expected declaration specifiers or '...' before string constant
     331 | MODULE_DESCRIPTION("Ultrasoc AXI COM driver");
         |                    ^~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:332:16: error: expected declaration specifiers or '...' before string constant
     332 | MODULE_LICENSE("Dual MIT/GPL");
         |                ^~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:333:15: error: expected declaration specifiers or '...' before string constant
     333 | MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:334:15: error: expected declaration specifiers or '...' before string constant
     334 | MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
         |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:32,
                    from include/linux/acpi.h:15,
                    from drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:30:
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:24: warning: 'axi_com_driver_exit' defined but not used [-Wunused-function]
     329 | module_platform_driver(axi_com_driver);
         |                        ^~~~~~~~~~~~~~
   include/linux/device/driver.h:264:20: note: in definition of macro 'module_driver'
     264 | static void __exit __driver##_exit(void) \
         |                    ^~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:24: warning: 'axi_com_driver_init' defined but not used [-Wunused-function]
     329 | module_platform_driver(axi_com_driver);
         |                        ^~~~~~~~~~~~~~
   include/linux/device/driver.h:259:19: note: in definition of macro 'module_driver'
     259 | static int __init __driver##_init(void) \
         |                   ^~~~~~~~
   drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c:329:1: note: in expansion of macro 'module_platform_driver'
     329 | module_platform_driver(axi_com_driver);
         | ^~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +/readl +42 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c

    37	
    38	static void axi_com_enable_hw(struct axi_com_drv_data *drvdata)
    39	{
    40		u32 val;
    41	
  > 42		val = readl(drvdata->base + AXIC_US_CTL);
    43		val |= AXIC_US_CTL_EN;
  > 44		writel(val, drvdata->base + AXIC_US_CTL);
    45	
    46		val = readl(drvdata->base + AXIC_DS_CTL);
    47		val |= AXIC_DS_CTL_EN;
    48		writel(val, drvdata->base + AXIC_DS_CTL);
    49	}
    50	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 59103 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers
  2021-06-15  9:34 ` [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers Qi Liu
@ 2021-06-23 22:51   ` Mathieu Poirier
  2021-06-24 12:43     ` liuqi (BA)
  0 siblings, 1 reply; 16+ messages in thread
From: Mathieu Poirier @ 2021-06-23 22:51 UTC (permalink / raw)
  To: Qi Liu
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight, linuxarm

Hi,

On Tue, Jun 15, 2021 at 05:34:41PM +0800, Qi Liu wrote:
> Ultrasoc trace module is a system level solution for both core tracing
> and SoC tracing. This patch brings in a documentation for ultrasoc
> framework and drivers. It simply introduces function of ultrasoc, a
> typical Ultrasoc system, and a driver framework for ultrasoc.
> 
> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> ---
>  Documentation/trace/ultrasoc-trace.rst | 209 +++++++++++++++++++++++++++++++++
>  1 file changed, 209 insertions(+)
>  create mode 100644 Documentation/trace/ultrasoc-trace.rst
> 
> diff --git a/Documentation/trace/ultrasoc-trace.rst b/Documentation/trace/ultrasoc-trace.rst
> new file mode 100644
> index 0000000..36d2df2
> --- /dev/null
> +++ b/Documentation/trace/ultrasoc-trace.rst
> @@ -0,0 +1,209 @@
> +=======================================================
> +Siemens Embedded Analytics - HW Assisted Tracing on SoC
> +=======================================================
> +   :Author:   Jonathan Zhou <Jonathan.zhouwen@huawei.com>
> +              Qi Liu <liuqi115@huawei.com>
> +   :Date:     January 16th, 2021
> +
> +Introduction
> +------------
> +
> +The Siemens Embedded Analytics Framework is system level solution for tracing
> +of multiple type SoC, this document is concerned with trace module. This module
> +has two main components: AXI Bus Communicator and System Memory Buffer.
> +
> +The AXI Communicator has upstream and downstream channels, the upstream channel
> +is used to transmit user configuration, and downstream channel to carry response
> +and trace data to the users.
> +
> +The System Memory Buffer provides a way to buffer and store messages in system
> +memory. It provides a capability to store messages received on its input message
> +interface to an area of system memory.
> +
> +A typical Siemens trace system would look like the following diagram:
> +                           @@@@@@@@@@@@@
> +                           @    CPU    @
> +                           @@@@@@@@@@@@@
> +                           #############
> +                           # Coresight #
> +                             #  ETM  #
> +                              #######
> +                                ###
> +                                 #
> +                                 |
> +                                 *
> +                    *******************************
> +                 *** AMBA Advanced Trace Bus (ATB) ***
> +                    ***************^***************
> +                          ===============    |
> +                           === FUNNEL ==<--- |
> +                              =======
> +                                 |
> +                                 *
> +                              @@@@@@@
> +                              @ TRC @
> +                               @@@@@
> +                                @@@
> +                                 @
> +                                 |
> +                                 *
> +    ************************************** *******************
> + ************************ Message BUS ***************************
> +    ******************^************************^****************
> +             |                               |
> +     @@@@@@@@@@@@@@@@@@                      |   @@@@@@@@@@@@
> +     @ Message Engine @                      |   @ JTAG COM @
> +     @@@@@@@@@@@@@@@@@@                      |    @@@@@@@@@@
> +       |            *                        |---> @@@@@@@@
> +       |            |                               @@@@@@
> +    @@@@@@@         |   @@@@@@@@@@@                    |
> +    @ SMB @         |   @ AXI COM @                  JTAG
> +     @@@@@          |--> @@@@@@@@@
> +      @@@--|              @@@@@@@
> +       @   |               @@@@@
> +           |                 |
> +           |                 |
> +           *                 *
> +  ***************************************************************
> + **************************** AMBA AXI  ****************************
> +  *****************************************************************
> +
> +Acronyms
> +---------------------------
> +
> +Acronyms:
> +
> +AXI-COM:     AXI Communicator
> +SMB:         System Memory Buffer
> +TRC:         Trace receiver
> +
> +Framework and implementation
> +------------------------------
> +
> +Siemens Embedded Analytics Framework is implemented as a platform device. The
> +platform device provides a global point to configure the Embedded Analytics
> +subsystem, and also provides a ``struct ultrasoc_com`` to manage AXI-COM and
> +SMB.
> +
> +AXI-COM and SMB are implemented as platform devices, each SCCL has one AXI-COM
> +device and one SMB device. AXI-COM and SMB can use the following API to register
> +into Embedded Analytics framework:
> +.. c:function:: struct ultrasoc_com *ultrasoc_register_com(struct device *root_dev, struct ultrasoc_com_descp *com_descp)
> +.. c:function:: void ultrasoc_unregister_com(struct ultrasoc_com *com);
> +
> +As TRC receives data from coresight ETM device, SMB can use the following API
> +to register into coresight framework as a sink device:
> +.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc);
> +.. c:function:: void coresight_unregister(struct coresight_device *csdev);
> +
> +Then users can get trace data by this path: ETM->funnel->SMB->System Memory.
> +More information about coresight framework can be found in
> +Documention/trace/coresight/coresight.rst.
> +
> +If everything goes well, the relationship of Embedded Analytics devices will be
> +described under the sysfs::
> +
> +    $# ls /sys/bus/platform/devices/
> +    <HID.Embedded Analytics>:00   <HID.axi-com>:00   <HID.smb>:00
> +    $# ls /sys/bus/platform/devices/<HID.Embedded Analytics>:00
> +    com_mux             firmware_node     power      <HID.axi-com>:00
> +    driver              message           subsystem  <HID.smb>:00
> +    driver_override     modalias          uevent
> +    $# ls /sys/bus/coresight/devices/
> +    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
> +    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
> +    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
> +    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
> +    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
> +    etm13    etm19    etm24    etm3     etm7     funnel3
> +    $# ls -l /sys/bus/coresight/devices/funnel0/connections/
> +    <file details> in:0 -> ../../../../system/cpu/cpu0/ARMHC500:00/etm0
> +    <file details> in:1 -> ../../../../system/cpu/cpu1/ARMHC500:01/etm1
> +    <file details> in:2 -> ../../../../system/cpu/cpu2/ARMHC500:02/etm2
> +    <file details> in:3 -> ../../../../system/cpu/cpu3/ARMHC500:03/etm3
> +    <file details> nr_links
> +    <file details> out:0 -> ../../../HISI0391:00/HISI03A1:00/sink_smb0
> +    $# ls -l /sys/bus/coresight/devices/sink_smb0/connections/
> +    <file details>  in:101 -> ../../../../ARMHC9FE:05/funnel5
> +    <file details>  in:114 -> ../../../../ARMHC9FE:07/funnel7
> +    <file details>  in:121 -> ../../../../ARMHC9FE:03/funnel3
> +    <file details>  in:39 -> ../../../../ARMHC9FE:00/funnel0
> +    <file details>  in:51 -> ../../../../ARMHC9FE:04/funnel4
> +    <file details>  in:61 -> ../../../../ARMHC9FE:06/funnel6
> +    <file details>  in:68 -> ../../../../ARMHC9FE:02/funnel2
> +    <file details>  in:89 -> ../../../../ARMHC9FE:01/funnel1
> +    <file details>  nr_links
> +
> +How to use the Embedded Analytics trace module
> +-----------------------------------------------
> +
> +There are two ways to use the Embedded Analytics trace module:
> +
> +1. interacting directly with the devices using the sysFS interface.
> +2. using the perf cmd line tools.
> +
> +1) Using the sysFS interface:
> +
> +Before trace collection can start, a coresight sink needs to be identified.
> +There is no limit on the amount of sinks (nor sources) that can be enabled at
> +any given moment.  As a generic operation, all device pertaining to the sink
> +class will have an "active" entry in sysfs::

I haven't looked at the rest of the patchset but unless you have changed that,
only one sink will be selected by the framework when operating from sysfs.
Regardless of the number of sinks that were enabled, the framework will pick the
first one it finds.

> +
> +    $# ls /sys/bus/coresight/devices/
> +    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
> +    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
> +    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
> +    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
> +    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
> +    etm13    etm19    etm24    etm3     etm7     funnel3
> +    $# ls /sys/bus/coresight/devices/sink_smb0
> +    connections  enable_sink  firmware_node  power  subsystem  uevent
> +    $# echo 1 > /sys/bus/coresight/devices/sink_smb0/enable_sink
> +    $# cat /sys/bus/coresight/devices/sink_smb0/enable_sink
> +    1
> +
> +When start trace collection, etm devices corresponding to the enabled sink
> +should be selected::
> +
> +    $# echo 1 > /sys/bus/coresight/devices/etm0/enable_source
> +    $# cat /sys/bus/coresight/devices/etm0/enable_source
> +    1
> +    $# cat /sys/bus/platform/devices/<HID.smb>:00/com_status
> +    com-type            : DOWN-ONLY
> +    service status      : stopped
> +    interrupt status    : 0x00000003
> +    write point         : 0x5437f400   <----- The write pointer is moving
> +
> +Trace collection is stopped the same way::
> +
> +    $# echo 0 > /sys/bus/coresight/devices/etm0/enable_source
> +    $# echo 0 > /sys/bus/coresight/devices/sink_smb0/enable_sink
> +
> +The content of the SMB buffer can be harvested directly from /dev::
> +
> +    $# dd if=/dev/sink_smb0 of=~/cstrace.bin
> +    5233+0 records in
> +    5233+0 records out
> +    2679296 bytes (2.7 MB) copied, 0.0131708 s, 203 MB/s
> +
> +    root:/sys/bus/coresight/devices#
> +
> +The file cstrace.bin can be decompressed using "ptm2human".
> +
> +2) Using perf framework:
> +
> +As SMB device has been registered with coresight framework, perf tool can be
> +used to control Embedded Analytics trace collection, and the method is similar
> +to using perf to do coresight trace collection.
> +
> +The only thing to note is, list of cpus should be correspond to the specified
> +sink device.
> +
> +Example usage of perf::
> +
> +	 $# ./perf list pmu
> +	 cs_etm//                                    [Kernel PMU event]
> +    $# ./perf record -e cs_etm/@sink_smb0/ -C 0 --per-thread sleep 2s
> +    [ perf record: Woken up 2 times to write data ]
> +    [ perf record: Captured and wrote 0.288 MB perf.data ]
> +    $# ./perf report

After reading all this and without looking at the rest of the patchset it seems
to me this work should go under drivers/hwtracing/coresight/.

There is a lot of code to review and as such it will take me a fair amount of
time to go through it all.  Comments will be scattered over several days (weeks)
- I will set you know when I am done.

Thanks,
Mathieu

> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers
  2021-06-23 22:51   ` Mathieu Poirier
@ 2021-06-24 12:43     ` liuqi (BA)
  2021-06-24 16:26       ` Mathieu Poirier
  0 siblings, 1 reply; 16+ messages in thread
From: liuqi (BA) @ 2021-06-24 12:43 UTC (permalink / raw)
  To: Mathieu Poirier, Linuxarm
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight

Hi Mathieu,

Thanks for reviewing this patch.

On 2021/6/24 6:51, Mathieu Poirier wrote:
> Hi,
> 
> On Tue, Jun 15, 2021 at 05:34:41PM +0800, Qi Liu wrote:
>> Ultrasoc trace module is a system level solution for both core tracing
>> and SoC tracing. This patch brings in a documentation for ultrasoc
>> framework and drivers. It simply introduces function of ultrasoc, a
>> typical Ultrasoc system, and a driver framework for ultrasoc.
>>
>> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> ---
>>   Documentation/trace/ultrasoc-trace.rst | 209 +++++++++++++++++++++++++++++++++
>>   1 file changed, 209 insertions(+)
>>   create mode 100644 Documentation/trace/ultrasoc-trace.rst
>>
>> diff --git a/Documentation/trace/ultrasoc-trace.rst b/Documentation/trace/ultrasoc-trace.rst
>> new file mode 100644
>> index 0000000..36d2df2
>> --- /dev/null
>> +++ b/Documentation/trace/ultrasoc-trace.rst
>> @@ -0,0 +1,209 @@
>> +=======================================================
>> +Siemens Embedded Analytics - HW Assisted Tracing on SoC
>> +=======================================================
>> +   :Author:   Jonathan Zhou <Jonathan.zhouwen@huawei.com>
>> +              Qi Liu <liuqi115@huawei.com>
>> +   :Date:     January 16th, 2021
>> +
>> +Introduction
>> +------------
>> +
>> +The Siemens Embedded Analytics Framework is system level solution for tracing
>> +of multiple type SoC, this document is concerned with trace module. This module
>> +has two main components: AXI Bus Communicator and System Memory Buffer.
>> +
>> +The AXI Communicator has upstream and downstream channels, the upstream channel
>> +is used to transmit user configuration, and downstream channel to carry response
>> +and trace data to the users.
>> +
>> +The System Memory Buffer provides a way to buffer and store messages in system
>> +memory. It provides a capability to store messages received on its input message
>> +interface to an area of system memory.
>> +
>> +A typical Siemens trace system would look like the following diagram:
>> +                           @@@@@@@@@@@@@
>> +                           @    CPU    @
>> +                           @@@@@@@@@@@@@
>> +                           #############
>> +                           # Coresight #
>> +                             #  ETM  #
>> +                              #######
>> +                                ###
>> +                                 #
>> +                                 |
>> +                                 *
>> +                    *******************************
>> +                 *** AMBA Advanced Trace Bus (ATB) ***
>> +                    ***************^***************
>> +                          ===============    |
>> +                           === FUNNEL ==<--- |
>> +                              =======
>> +                                 |
>> +                                 *
>> +                              @@@@@@@
>> +                              @ TRC @
>> +                               @@@@@
>> +                                @@@
>> +                                 @
>> +                                 |
>> +                                 *
>> +    ************************************** *******************
>> + ************************ Message BUS ***************************
>> +    ******************^************************^****************
>> +             |                               |
>> +     @@@@@@@@@@@@@@@@@@                      |   @@@@@@@@@@@@
>> +     @ Message Engine @                      |   @ JTAG COM @
>> +     @@@@@@@@@@@@@@@@@@                      |    @@@@@@@@@@
>> +       |            *                        |---> @@@@@@@@
>> +       |            |                               @@@@@@
>> +    @@@@@@@         |   @@@@@@@@@@@                    |
>> +    @ SMB @         |   @ AXI COM @                  JTAG
>> +     @@@@@          |--> @@@@@@@@@
>> +      @@@--|              @@@@@@@
>> +       @   |               @@@@@
>> +           |                 |
>> +           |                 |
>> +           *                 *
>> +  ***************************************************************
>> + **************************** AMBA AXI  ****************************
>> +  *****************************************************************
>> +
>> +Acronyms
>> +---------------------------
>> +
>> +Acronyms:
>> +
>> +AXI-COM:     AXI Communicator
>> +SMB:         System Memory Buffer
>> +TRC:         Trace receiver
>> +
>> +Framework and implementation
>> +------------------------------
>> +
>> +Siemens Embedded Analytics Framework is implemented as a platform device. The
>> +platform device provides a global point to configure the Embedded Analytics
>> +subsystem, and also provides a ``struct ultrasoc_com`` to manage AXI-COM and
>> +SMB.
>> +
>> +AXI-COM and SMB are implemented as platform devices, each SCCL has one AXI-COM
>> +device and one SMB device. AXI-COM and SMB can use the following API to register
>> +into Embedded Analytics framework:
>> +.. c:function:: struct ultrasoc_com *ultrasoc_register_com(struct device *root_dev, struct ultrasoc_com_descp *com_descp)
>> +.. c:function:: void ultrasoc_unregister_com(struct ultrasoc_com *com);
>> +
>> +As TRC receives data from coresight ETM device, SMB can use the following API
>> +to register into coresight framework as a sink device:
>> +.. c:function:: struct coresight_device *coresight_register(struct coresight_desc *desc);
>> +.. c:function:: void coresight_unregister(struct coresight_device *csdev);
>> +
>> +Then users can get trace data by this path: ETM->funnel->SMB->System Memory.
>> +More information about coresight framework can be found in
>> +Documention/trace/coresight/coresight.rst.
>> +
>> +If everything goes well, the relationship of Embedded Analytics devices will be
>> +described under the sysfs::
>> +
>> +    $# ls /sys/bus/platform/devices/
>> +    <HID.Embedded Analytics>:00   <HID.axi-com>:00   <HID.smb>:00
>> +    $# ls /sys/bus/platform/devices/<HID.Embedded Analytics>:00
>> +    com_mux             firmware_node     power      <HID.axi-com>:00
>> +    driver              message           subsystem  <HID.smb>:00
>> +    driver_override     modalias          uevent
>> +    $# ls /sys/bus/coresight/devices/
>> +    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
>> +    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
>> +    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
>> +    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
>> +    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
>> +    etm13    etm19    etm24    etm3     etm7     funnel3
>> +    $# ls -l /sys/bus/coresight/devices/funnel0/connections/
>> +    <file details> in:0 -> ../../../../system/cpu/cpu0/ARMHC500:00/etm0
>> +    <file details> in:1 -> ../../../../system/cpu/cpu1/ARMHC500:01/etm1
>> +    <file details> in:2 -> ../../../../system/cpu/cpu2/ARMHC500:02/etm2
>> +    <file details> in:3 -> ../../../../system/cpu/cpu3/ARMHC500:03/etm3
>> +    <file details> nr_links
>> +    <file details> out:0 -> ../../../HISI0391:00/HISI03A1:00/sink_smb0
>> +    $# ls -l /sys/bus/coresight/devices/sink_smb0/connections/
>> +    <file details>  in:101 -> ../../../../ARMHC9FE:05/funnel5
>> +    <file details>  in:114 -> ../../../../ARMHC9FE:07/funnel7
>> +    <file details>  in:121 -> ../../../../ARMHC9FE:03/funnel3
>> +    <file details>  in:39 -> ../../../../ARMHC9FE:00/funnel0
>> +    <file details>  in:51 -> ../../../../ARMHC9FE:04/funnel4
>> +    <file details>  in:61 -> ../../../../ARMHC9FE:06/funnel6
>> +    <file details>  in:68 -> ../../../../ARMHC9FE:02/funnel2
>> +    <file details>  in:89 -> ../../../../ARMHC9FE:01/funnel1
>> +    <file details>  nr_links
>> +
>> +How to use the Embedded Analytics trace module
>> +-----------------------------------------------
>> +
>> +There are two ways to use the Embedded Analytics trace module:
>> +
>> +1. interacting directly with the devices using the sysFS interface.
>> +2. using the perf cmd line tools.
>> +
>> +1) Using the sysFS interface:
>> +
>> +Before trace collection can start, a coresight sink needs to be identified.
>> +There is no limit on the amount of sinks (nor sources) that can be enabled at
>> +any given moment.  As a generic operation, all device pertaining to the sink
>> +class will have an "active" entry in sysfs::
> 
> I haven't looked at the rest of the patchset but unless you have changed that,
> only one sink will be selected by the framework when operating from sysfs.
> Regardless of the number of sinks that were enabled, the framework will pick the
> first one it finds.
> 
Yes, framework only choose the first sink device if there are several 
sinks. I'll change the description in document in next version, thanks.

>> +
>> +    $# ls /sys/bus/coresight/devices/
>> +    etm0     etm14    etm2     etm25    etm30    etm8       funnel4
>> +    etm1     etm15    etm20    etm26    etm31    etm9       funnel5
>> +    etm10    etm16    etm21    etm27    etm4     funnel0    funnel6
>> +    etm11    etm17    etm22    etm28    etm5     funnel1    funnel7
>> +    etm12    etm18    etm23    etm29    etm6     funnel2    sink_smb0
>> +    etm13    etm19    etm24    etm3     etm7     funnel3
>> +    $# ls /sys/bus/coresight/devices/sink_smb0
>> +    connections  enable_sink  firmware_node  power  subsystem  uevent
>> +    $# echo 1 > /sys/bus/coresight/devices/sink_smb0/enable_sink
>> +    $# cat /sys/bus/coresight/devices/sink_smb0/enable_sink
>> +    1
>> +
>> +When start trace collection, etm devices corresponding to the enabled sink
>> +should be selected::
>> +
>> +    $# echo 1 > /sys/bus/coresight/devices/etm0/enable_source
>> +    $# cat /sys/bus/coresight/devices/etm0/enable_source
>> +    1
>> +    $# cat /sys/bus/platform/devices/<HID.smb>:00/com_status
>> +    com-type            : DOWN-ONLY
>> +    service status      : stopped
>> +    interrupt status    : 0x00000003
>> +    write point         : 0x5437f400   <----- The write pointer is moving
>> +
>> +Trace collection is stopped the same way::
>> +
>> +    $# echo 0 > /sys/bus/coresight/devices/etm0/enable_source
>> +    $# echo 0 > /sys/bus/coresight/devices/sink_smb0/enable_sink
>> +
>> +The content of the SMB buffer can be harvested directly from /dev::
>> +
>> +    $# dd if=/dev/sink_smb0 of=~/cstrace.bin
>> +    5233+0 records in
>> +    5233+0 records out
>> +    2679296 bytes (2.7 MB) copied, 0.0131708 s, 203 MB/s
>> +
>> +    root:/sys/bus/coresight/devices#
>> +
>> +The file cstrace.bin can be decompressed using "ptm2human".
>> +
>> +2) Using perf framework:
>> +
>> +As SMB device has been registered with coresight framework, perf tool can be
>> +used to control Embedded Analytics trace collection, and the method is similar
>> +to using perf to do coresight trace collection.
>> +
>> +The only thing to note is, list of cpus should be correspond to the specified
>> +sink device.
>> +
>> +Example usage of perf::
>> +
>> +	 $# ./perf list pmu
>> +	 cs_etm//                                    [Kernel PMU event]
>> +    $# ./perf record -e cs_etm/@sink_smb0/ -C 0 --per-thread sleep 2s
>> +    [ perf record: Woken up 2 times to write data ]
>> +    [ perf record: Captured and wrote 0.288 MB perf.data ]
>> +    $# ./perf report
> 
> After reading all this and without looking at the rest of the patchset it seems
> to me this work should go under drivers/hwtracing/coresight/.
> 

So how about drivers/hwtracing/coresight/ultrasoc?

> There is a lot of code to review and as such it will take me a fair amount of
> time to go through it all.  Comments will be scattered over several days (weeks)
> - I will set you know when I am done.
> 
> Thanks,
> Mathieu

Ok, thanks for revewing this patchset

Qi
> 
>> -- 
>> 2.7.4
>>
> .
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers
  2021-06-24 12:43     ` liuqi (BA)
@ 2021-06-24 16:26       ` Mathieu Poirier
  0 siblings, 0 replies; 16+ messages in thread
From: Mathieu Poirier @ 2021-06-24 16:26 UTC (permalink / raw)
  To: liuqi (BA)
  Cc: Linuxarm, Alexander Shishkin, Suzuki K. Poulose, Jonathan Zhou,
	f.fangjian, Linux Kernel Mailing List, Coresight ML

> >> +Example usage of perf::
> >> +
> >> +     $# ./perf list pmu
> >> +     cs_etm//                                    [Kernel PMU event]
> >> +    $# ./perf record -e cs_etm/@sink_smb0/ -C 0 --per-thread sleep 2s
> >> +    [ perf record: Woken up 2 times to write data ]
> >> +    [ perf record: Captured and wrote 0.288 MB perf.data ]
> >> +    $# ./perf report
> >
> > After reading all this and without looking at the rest of the patchset it seems
> > to me this work should go under drivers/hwtracing/coresight/.
> >
>
> So how about drivers/hwtracing/coresight/ultrasoc?
>

It's hard to say at this time - I'll advise further once I have
reviewed the other patches.

> > There is a lot of code to review and as such it will take me a fair amount of
> > time to go through it all.  Comments will be scattered over several days (weeks)
> > - I will set you know when I am done.
> >
> > Thanks,
> > Mathieu
>
> Ok, thanks for revewing this patchset
>
> Qi
> >
> >> --
> >> 2.7.4
> >>
> > .
> >
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
  2021-06-16 18:04   ` kernel test robot
@ 2021-06-24 22:47   ` Suzuki K Poulose
  2021-07-08  8:25     ` liuqi (BA)
  2021-06-29 20:50   ` Mathieu Poirier
  2 siblings, 1 reply; 16+ messages in thread
From: Suzuki K Poulose @ 2021-06-24 22:47 UTC (permalink / raw)
  To: Qi Liu, alexander.shishkin, mathieu.poirier, jonathan.zhouwen,
	f.fangjian
  Cc: linux-kernel, coresight, linuxarm

Hi Qi

On 15/06/2021 10:34, Qi Liu wrote:
> This patch adds driver for System Memory Buffer. It includes
> a platform driver for the SMB device.
> 
> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> ---
>   drivers/hwtracing/ultrasoc/Kconfig        |   9 +
>   drivers/hwtracing/ultrasoc/Makefile       |   3 +
>   drivers/hwtracing/ultrasoc/ultrasoc-smb.c | 663 ++++++++++++++++++++++++++++++
>   drivers/hwtracing/ultrasoc/ultrasoc-smb.h | 182 ++++++++
>   4 files changed, 857 insertions(+)
>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h
> 

> +/*
> + * Coresight doesn't export the following
> + * structures(cs_mode,cs_buffers,etm_event_data),
> + * so we redefine a copy here.
> + */

Please do not duplicate them. This indicates, either :

  - You need to place your driver under coresight

  OR

  - Export the required definitions.

> +enum cs_mode {
> +	CS_MODE_DISABLED,
> +	CS_MODE_SYSFS,
> +	CS_MODE_PERF,
> +};
> +

> +struct cs_buffers {
> +	unsigned int		cur;
> +	unsigned int		nr_pages;
> +	unsigned long		offset;
> +	local_t			data_size;
> +	bool			snapshot;
> +	void			**data_pages;
> +};
> +

Why does this need to be replicated ?

> +struct etm_event_data {
> +	struct work_struct work;
> +	cpumask_t mask;
> +	void *snk_config;
> +	struct list_head * __percpu *path;
> +};
> +
> +#if IS_ENABLED(CONFIG_CORESIGHT)
> +int etm_perf_symlink(struct coresight_device *csdev, bool link);
> +int etm_perf_add_symlink_sink(struct coresight_device *csdev);
> +void etm_perf_del_symlink_sink(struct coresight_device *csdev);
> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
> +{
> +	struct etm_event_data *data = perf_get_aux(handle);
> +
> +	if (data)
> +		return data->snk_config;
> +	return NULL;
> +}
> +#else
> +static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
> +{ return -EINVAL; }
> +int etm_perf_add_symlink_sink(struct coresight_device *csdev)
> +{ return -EINVAL; }
> +void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
> +{
> +	return NULL;
> +}
> +
> +#endif /* CONFIG_CORESIGHT */
> +
> +#endif
> 

Suzuki

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
  2021-06-16 18:04   ` kernel test robot
  2021-06-24 22:47   ` Suzuki K Poulose
@ 2021-06-29 20:50   ` Mathieu Poirier
  2021-07-08  8:47     ` liuqi (BA)
  2 siblings, 1 reply; 16+ messages in thread
From: Mathieu Poirier @ 2021-06-29 20:50 UTC (permalink / raw)
  To: Qi Liu
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight, linuxarm

Hi Qi,

On Tue, Jun 15, 2021 at 05:34:44PM +0800, Qi Liu wrote:
> This patch adds driver for System Memory Buffer. It includes
> a platform driver for the SMB device.
> 
> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> ---
>  drivers/hwtracing/ultrasoc/Kconfig        |   9 +
>  drivers/hwtracing/ultrasoc/Makefile       |   3 +
>  drivers/hwtracing/ultrasoc/ultrasoc-smb.c | 663 ++++++++++++++++++++++++++++++
>  drivers/hwtracing/ultrasoc/ultrasoc-smb.h | 182 ++++++++
>  4 files changed, 857 insertions(+)
>  create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
>  create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h
> 
> diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
> index 77429f3..8899949 100644
> --- a/drivers/hwtracing/ultrasoc/Kconfig
> +++ b/drivers/hwtracing/ultrasoc/Kconfig
> @@ -22,4 +22,13 @@ config ULTRASOC_AXI_COM
>  	  the upstream channel is used to transmit user configuration, and
>  	  downstream channel to carry response and trace data to the users.
>  
> +config ULTRASOC_SMB
> +	tristate "Ultrasoc System memory buffer drivers"
> +	help
> +	  This config enables support for Ultrasoc System Memory Buffer
> +	  drivers. The System Memory Buffer provides a way to buffer and
> +	  store messages in system memory. It provides a capability to
> +	  store messages received on its input message interface to an
> +	  area of system memory.
> +
>  endif
> diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
> index 54711a7b..b174ca8 100644
> --- a/drivers/hwtracing/ultrasoc/Makefile
> +++ b/drivers/hwtracing/ultrasoc/Makefile
> @@ -8,3 +8,6 @@ ultrasoc-drv-objs := ultrasoc.o
>  
>  obj-$(CONFIG_ULTRASOC_AXI_COM) += ultrasoc-axi-com-drv.o
>  ultrasoc-axi-com-drv-objs := ultrasoc-axi-com.o
> +
> +obj-$(CONFIG_ULTRASOC_SMB) += ultrasoc-smb-drv.o
> +ultrasoc-smb-drv-objs := ultrasoc-smb.o
> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-smb.c b/drivers/hwtracing/ultrasoc/ultrasoc-smb.c
> new file mode 100644
> index 0000000..ce03f5e
> --- /dev/null
> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-smb.c
> @@ -0,0 +1,663 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
> + * charge, to any person obtaining a copy of this software and associated
> + * documentation files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use, copy, modify,
> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
> + * and to permit persons to whom the Software is furnished to do so, subject
> + * to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Code herein communicates with and accesses proprietary hardware which is
> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
> + * Software Ltd.
> + *
> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
> + * their intellectual property. This paragraph may not be removed or modified
> + * in any way without permission from Siemens Digital Industries Software Ltd.
> + */
> +
> +#include <linux/circ_buf.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_device.h>
> +
> +#include "ultrasoc-smb.h"
> +
> +static inline int smb_hw_buffer_empty(struct smb_drv_data *drvdata)
> +{
> +	u32 buf_status = readl(drvdata->base + SMB_LB_INT_STS);
> +
> +	return buf_status & BIT(0) ? 0 : 1;
> +}
> +
> +static inline int smb_buffer_pointer_pos(struct smb_drv_data *drvdata)
> +{
> +	u32 wr_offset, rd_offset;
> +
> +	wr_offset = readl(drvdata->base + SMB_LB_WR_ADDR);
> +	rd_offset = readl(drvdata->base + SMB_LB_RD_ADDR);
> +	return wr_offset == rd_offset;
> +}
> +
> +static inline int smb_hw_buffer_full(struct smb_drv_data *drvdata)
> +{
> +	return smb_buffer_pointer_pos(drvdata) && !smb_hw_buffer_empty(drvdata);
> +}
> +
> +static inline void smb_clear_buf_status(struct smb_drv_data *drvdata)
> +{
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +
> +	if (smb_buffer_pointer_pos(drvdata) && !sdb->to_copy)
> +		writel(0xf, drvdata->base + SMB_LB_INT_STS);
> +}
> +
> +static void smb_update_hw_write_size(struct smb_drv_data *drvdata)
> +{
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +	u32 write_offset, write_base;
> +
> +	sdb->lost = false;
> +	writel(0x1, drvdata->base + SMB_LB_PURGE);
> +	if (smb_hw_buffer_empty(drvdata)) {
> +		sdb->to_copy = 0;
> +		return;
> +	}
> +
> +	if (smb_hw_buffer_full(drvdata)) {
> +		sdb->to_copy = sdb->buf_size;
> +		return;
> +	}
> +
> +	write_base = sdb->buf_base_phys & SMB_BUF_WRITE_BASE;
> +	write_offset = readl(drvdata->base + SMB_LB_WR_ADDR) - write_base;
> +	sdb->to_copy = CIRC_CNT(write_offset, sdb->rd_offset, sdb->buf_size);
> +}
> +
> +static int smb_open(struct inode *inode, struct file *file)
> +{
> +	struct smb_drv_data *drvdata = container_of(file->private_data,
> +			struct smb_drv_data, miscdev);
> +
> +	if (local_cmpxchg(&drvdata->reading, 0, 1))
> +		return -EBUSY;
> +
> +	smb_update_hw_write_size(drvdata);
> +	return 0;
> +}
> +
> +static ssize_t smb_read(struct file *file, char __user *data,
> +			size_t len, loff_t *ppos)
> +{
> +	struct smb_drv_data *drvdata = container_of(file->private_data,
> +			struct smb_drv_data, miscdev);
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +	struct device *dev = &drvdata->csdev->dev;
> +	unsigned long to_copy = sdb->to_copy;
> +
> +	if (!to_copy) {
> +		smb_update_hw_write_size(drvdata);
> +		to_copy = sdb->to_copy;
> +		if (!to_copy)
> +			return to_copy;
> +	}
> +
> +	to_copy = min(to_copy, len);
> +	/*
> +	 * if the read needs to cross the boundary of the data buffer, copy
> +	 * last datas of the buffer to user
> +	 */
> +	if (sdb->rd_offset + to_copy > sdb->buf_size)
> +		to_copy = sdb->buf_size - sdb->rd_offset;
> +
> +	if (copy_to_user(data, (void *)sdb->buf_base + sdb->rd_offset, to_copy)) {
> +		dev_dbg(dev, "Failed to copy data to user.\n");
> +		return -EFAULT;
> +	}
> +
> +	*ppos += to_copy;
> +	sdb->rd_offset += to_copy;
> +	sdb->rd_offset %= sdb->buf_size;
> +	sdb->to_copy -= to_copy;
> +
> +	/* update the read point */
> +	writel(sdb->buf_base_phys + sdb->rd_offset,
> +	       drvdata->base + SMB_LB_RD_ADDR);
> +	smb_clear_buf_status(drvdata);
> +	dev_dbg(dev, "%lu bytes copied.\n", to_copy);
> +
> +	return to_copy;
> +}
> +
> +static int smb_release(struct inode *inode, struct file *file)
> +{
> +	struct smb_drv_data *drvdata = container_of(file->private_data,
> +			struct smb_drv_data, miscdev);
> +	local_set(&drvdata->reading, 0);
> +	return 0;
> +}
> +
> +static const struct file_operations smb_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= smb_open,
> +	.read		= smb_read,
> +	.release	= smb_release,
> +	.llseek		= no_llseek,
> +};
> +
> +static ssize_t smb_show_status(struct ultrasoc_com *com, char *buf,
> +			       ssize_t wr_size)
> +{
> +	struct smb_drv_data *drvdata;
> +	u32 value;
> +
> +	drvdata = dev_get_drvdata(com->dev);
> +	value = readl(drvdata->base + SMB_LB_INT_STS);
> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: 0x%08x\n",
> +				 "interrupt status", value);
> +	value = readl(drvdata->base + SMB_LB_WR_ADDR);
> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "write point",
> +				 value);
> +	value = readl(drvdata->base + SMB_LB_RD_ADDR);
> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "read point",
> +				 value);

This will not work.  The sysfs interface requires one line per entry.  Please
look at what other coresight drivers do in that area.

> +
> +	return wr_size;
> +}
> +
> +static int smb_init_data_buffer(struct platform_device *pdev,
> +				struct smb_data_buffer *sdb)
> +{
> +	struct resource *res;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (IS_ERR(res)) {
> +		dev_err(&pdev->dev, "SMB device without data buffer.\n");
> +		return -EINVAL;
> +	}
> +
> +	sdb->buf_base_phys = res->start;
> +	sdb->buf_size = resource_size(res);
> +	if (sdb->buf_size == 0)
> +		return -EINVAL;
> +
> +	sdb->buf_base = ioremap_cache(sdb->buf_base_phys, sdb->buf_size);

Why no using devm_ioremap_resource() ?

> +	if (sdb->buf_base == NULL)
> +		return -ENOMEM;
> +
> +	sdb->buf_cfg_mode = SMB_BUF_CFG_STREAMING;

As far as I can tell there is no point in keeping the value of
SMB_BUF_CFG_STREAMING in the smb_data_buffer since it isn't used for anything
else other than setting a HW register in smb_set_default_hw().

> +	return 0;
> +}
> +
> +static void smb_release_data_buffer(struct smb_drv_data *drvdata)
> +{
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +
> +	if (sdb->buf_base)
> +		iounmap(sdb->buf_base);
> +}
> +
> +static struct uscom_ops smb_ops = {
> +	.com_status = smb_show_status,
> +	.put_raw_msg = NULL,
> +};
> +
> +static int smb_set_buffer(struct coresight_device *csdev,
> +		struct perf_output_handle *handle);
> +
> +static void smb_enable_hw(struct smb_drv_data *drvdata)
> +{
> +	writel(0x1, drvdata->base + SMB_GLOBAL_EN);
> +}
> +
> +static void smb_disable_hw(struct smb_drv_data *drvdata)
> +{
> +	writel(0x1, drvdata->base + SMB_LB_PURGE);
> +	writel(0x0, drvdata->base + SMB_GLOBAL_EN);
> +}
> +
> +static int smb_enable_sysfs(struct coresight_device *csdev)
> +{
> +	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	WARN_ON_ONCE(drvdata == NULL);
> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +
> +	/* Don't messup with perf sessions. */
> +	if (drvdata->mode == CS_MODE_PERF) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	if (drvdata->mode == CS_MODE_DISABLED) {
> +		smb_enable_hw(drvdata);
> +		drvdata->mode = CS_MODE_SYSFS;
> +	}
> +	atomic_inc(csdev->refcnt);
> +out:
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +	return ret;
> +}
> +
> +static int smb_enable_perf(struct coresight_device *csdev, void *data)
> +{
> +	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	struct device *dev = &drvdata->csdev->dev;
> +	struct perf_output_handle *handle = data;
> +	unsigned long flags;
> +	int ret = 0;
> +	pid_t pid;
> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +	if (drvdata->mode == CS_MODE_SYSFS) {
> +		dev_err(dev, "Device is already in used by sysfs.\n");
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	/* Get a handle on the pid of the target process*/
> +	pid = task_pid_nr(handle->event->owner);
> +	if (drvdata->pid != -1 && drvdata->pid != pid) {
> +		ret = -EBUSY;
> +		goto out;
> +	}
> +
> +	/*
> +	 * No HW configuration is needed if the sink is already in
> +	 * use for this session.
> +	 */
> +	if (drvdata->pid == pid) {
> +		atomic_inc(csdev->refcnt);
> +		goto out;
> +	}
> +
> +	/*
> +	 * We don't have an internal state to clean up if we fail to setup
> +	 * the perf buffer. So we can perform the step before we turn the
> +	 * ETB on and leave without cleaning up.
> +	 */
> +	ret = smb_set_buffer(csdev, handle);
> +	if (ret)
> +		goto out;
> +
> +	smb_enable_hw(drvdata);
> +	drvdata->pid = pid;
> +	drvdata->mode = CS_MODE_PERF;
> +	atomic_inc(csdev->refcnt);
> +out:
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +	return ret;
> +}
> +
> +static int smb_enable(struct coresight_device *csdev, u32 mode, void *data)
> +{
> +	int ret;
> +
> +	switch (mode) {
> +	case CS_MODE_SYSFS:
> +		ret = smb_enable_sysfs(csdev);
> +		break;
> +	case CS_MODE_PERF:
> +		ret = smb_enable_perf(csdev, data);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	if (ret)
> +		return ret;
> +
> +	dev_dbg(&csdev->dev, "Ultrasoc smb enabled.\n");
> +
> +	return 0;
> +}
> +
> +static int smb_disable(struct coresight_device *csdev)
> +{
> +	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&drvdata->spinlock, flags);
> +
> +	if (atomic_dec_return(csdev->refcnt)) {
> +		spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +		return -EBUSY;
> +	}
> +
> +	/* Complain if we (somehow) got out of sync */
> +	WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
> +	smb_disable_hw(drvdata);
> +
> +	/* Dissociate from the target process. */
> +	drvdata->pid = -1;
> +	drvdata->mode = CS_MODE_DISABLED;
> +	spin_unlock_irqrestore(&drvdata->spinlock, flags);
> +
> +	dev_dbg(&csdev->dev, "Ultrasoc smb disabled.\n");
> +	return 0;
> +}
> +
> +static void smb_set_default_hw(struct smb_drv_data *drvdata)
> +{
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +	u32 value, base_hi, base_lo, limit_lo;
> +
> +	/* first disable smb and clear the status of SMB buffer */
> +	smb_disable_hw(drvdata);
> +	smb_clear_buf_status(drvdata);
> +
> +	/* using smb in single-end mode, and set other configures default */
> +	value = sdb->buf_cfg_mode | SMB_BUF_SINGLE_END | SMB_BUF_ENABLE;
> +	writel(value, drvdata->base + SMB_LB_CFG_LO);
> +	value = SMB_MSG_FILTER(0x0, 0xff);
> +	writel(value, drvdata->base + SMB_LB_CFG_HI);
> +
> +	writel(HISI_SMB_GLOBAL_CFG, drvdata->base + SMB_GLOBAL_CFG);
> +	writel(HISI_SMB_GLB_INT_CFG, drvdata->base + SMB_GLOBAL_INT);
> +	writel(HISI_SMB_BUF_INT_CFG, drvdata->base + SMB_LB_INT_CTRL);
> +
> +	/* config hardware registers according to physical base of SMB buffer */
> +	base_hi = sdb->buf_base_phys >> 32;
> +	base_lo = sdb->buf_base_phys & SMB_BUF_WRITE_BASE;
> +	limit_lo = base_lo + sdb->buf_size;
> +	writel(base_lo, drvdata->base + SMB_LB_BASE_LO);
> +	writel(base_hi, drvdata->base + SMB_LB_BASE_HI);
> +	writel(limit_lo, drvdata->base + SMB_LB_LIMIT);
> +
> +	/* initial hardware read-ptr address*/
> +	writel(base_lo, drvdata->base + SMB_LB_RD_ADDR);
> +}
> +
> +static void *smb_alloc_buffer(struct coresight_device *csdev,
> +		struct perf_event *event, void **pages,
> +		int nr_pages, bool overwrite)
> +{
> +	struct cs_buffers *buf;
> +	int node;
> +
> +	node = (event->cpu == -1) ? NUMA_NO_NODE : cpu_to_node(event->cpu);
> +	buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node);
> +	if (!buf)
> +		return NULL;
> +
> +	buf->snapshot = overwrite;
> +	buf->nr_pages = nr_pages;
> +	buf->data_pages = pages;
> +
> +	return buf;
> +}
> +
> +static void smb_free_buffer(void *config)
> +{
> +	struct cs_buffers *buf = config;
> +
> +	kfree(buf);
> +}
> +
> +static int smb_set_buffer(struct coresight_device *csdev,
> +		struct perf_output_handle *handle)
> +{
> +	struct cs_buffers *buf = etm_perf_sink_config(handle);
> +	u32 head;
> +
> +	if (!buf)
> +		return -EINVAL;
> +
> +	/* wrap head around to the amount of space we have */
> +	head = handle->head & ((buf->nr_pages << PAGE_SHIFT) - 1);
> +
> +	/* find the page to write to and offset within that page */
> +	buf->cur = head / PAGE_SIZE;
> +	buf->offset = head % PAGE_SIZE;
> +
> +	local_set(&buf->data_size, 0);
> +
> +	return 0;
> +}
> +
> +static void smb_sync_perf_buffer(struct smb_drv_data *drvdata,
> +				 struct cs_buffers *buf, unsigned long to_copy)
> +{
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +	char **dst_pages = (char **)buf->data_pages;
> +	u32 buf_offset = buf->offset;
> +	u32 cur = buf->cur;
> +	u32 bytes;
> +
> +	while (to_copy > 0) {
> +		/*
> +		 * if the read needs to cross the boundary of the data buffer,
> +		 * copy last datas of the buffer to user
> +		 */
> +		if (sdb->rd_offset + PAGE_SIZE - buf_offset > sdb->buf_size)
> +			bytes = sdb->buf_size - sdb->rd_offset;
> +		else
> +			bytes = min(to_copy, PAGE_SIZE - buf_offset);
> +
> +		memcpy_fromio(dst_pages[cur] + buf_offset,
> +		       sdb->buf_base + sdb->rd_offset, bytes);
> +
> +		buf_offset += bytes;
> +		if (buf_offset >= PAGE_SIZE) {
> +			buf_offset = 0;
> +			cur++;
> +			cur %= buf->nr_pages;
> +		}
> +		to_copy -= bytes;
> +		/* ensure memcpy finished before update the read pointer */
> +		sdb->rd_offset += bytes;
> +		sdb->rd_offset %= sdb->buf_size;
> +	}
> +
> +	writel(sdb->buf_base_phys + sdb->rd_offset,
> +	       drvdata->base + SMB_LB_RD_ADDR);
> +	sdb->to_copy = to_copy;
> +}
> +
> +static unsigned long smb_update_buffer(struct coresight_device *csdev,
> +		struct perf_output_handle *handle, void *sink_config)
> +{
> +	struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
> +	struct smb_data_buffer *sdb = &drvdata->smb_db;
> +	struct cs_buffers *buf = sink_config;
> +	u64 to_copy;
> +
> +	if (!buf)
> +		return 0;
> +
> +	smb_update_hw_write_size(drvdata);
> +	to_copy = sdb->to_copy;
> +	if (to_copy > handle->size) {
> +		sdb->rd_offset += (to_copy - handle->size);
> +		sdb->rd_offset %= sdb->buf_size;
> +		to_copy = handle->size;
> +		sdb->lost = true;
> +	}
> +
> +	smb_sync_perf_buffer(drvdata, buf, to_copy);
> +	smb_clear_buf_status(drvdata);
> +	if (!buf->snapshot && sdb->lost)
> +		perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
> +
> +	return to_copy;
> +}
> +
> +static const struct coresight_ops_sink smb_cs_ops = {
> +	.enable		= smb_enable,
> +	.disable	= smb_disable,
> +	.alloc_buffer	= smb_alloc_buffer,
> +	.free_buffer	= smb_free_buffer,
> +	.update_buffer	= smb_update_buffer,
> +};
> +
> +static const struct coresight_ops cs_ops = {
> +	.sink_ops	= &smb_cs_ops,
> +};
> +
> +static int smb_init_res(struct platform_device *pdev,
> +			struct smb_drv_data *drvdata)
> +{
> +	struct smb_data_buffer *sdb;
> +	int ret;
> +
> +	sdb = &drvdata->smb_db;
> +	drvdata->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(drvdata->base)) {
> +		dev_err(&pdev->dev, "Failed to ioremap resource.\n");
> +		return PTR_ERR(drvdata->base);
> +	}
> +
> +	ret = smb_init_data_buffer(pdev, sdb);
> +	if (ret)
> +		dev_err(&pdev->dev, "Failed to init buffer, ret = %d.\n", ret);
> +
> +	return ret;
> +}
> +
> +DEFINE_CORESIGHT_DEVLIST(sink_devs, "sink_smb");
> +static int smb_register_sink(struct platform_device *pdev,
> +			     struct smb_drv_data *drvdata)
> +{
> +	struct coresight_platform_data *pdata = NULL;
> +	struct coresight_desc desc = { 0 };
> +	int ret;
> +
> +	pdata = coresight_get_platform_data(&pdev->dev);
> +	if (IS_ERR(pdata))
> +		return PTR_ERR(pdata);
> +
> +	drvdata->dev->platform_data = pdata;
> +	desc.type = CORESIGHT_DEV_TYPE_SINK;
> +	desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
> +	desc.ops = &cs_ops;
> +	desc.pdata = pdata;
> +	desc.dev = &pdev->dev;
> +	desc.name = coresight_alloc_device_name(&sink_devs, &pdev->dev);
> +	if (!desc.name) {
> +		dev_err(&pdev->dev, "Failed to alloc coresight device name.");
> +		return -ENOMEM;
> +	}
> +
> +	drvdata->csdev = coresight_register(&desc);
> +	if (IS_ERR(drvdata->csdev))
> +		return PTR_ERR(drvdata->csdev);
> +
> +	drvdata->miscdev.name = desc.name;
> +	drvdata->miscdev.minor = MISC_DYNAMIC_MINOR;
> +	drvdata->miscdev.fops = &smb_fops;
> +	ret = misc_register(&drvdata->miscdev);
> +	if (ret) {
> +		coresight_unregister(drvdata->csdev);
> +		dev_err(&pdev->dev, "Failed to register misc, ret=%d\n", ret);
> +	}
> +
> +	return ret;
> +}
> +
> +static void smb_unregister_sink(struct smb_drv_data *drvdata)
> +{
> +	misc_deregister(&drvdata->miscdev);
> +	coresight_unregister(drvdata->csdev);
> +}
> +
> +static int smb_config_com_descp(struct platform_device *pdev,
> +				struct smb_drv_data *drvdata)
> +{
> +	struct device *parent = pdev->dev.parent;
> +	struct ultrasoc_com_descp com_descp = {0};
> +	struct device *dev = &pdev->dev;
> +	struct ultrasoc_com *com;
> +
> +	com_descp.name = pdev->name;
> +	com_descp.com_type = ULTRASOC_COM_TYPE_DOWN;
> +	com_descp.com_dev = dev;
> +	com_descp.uscom_ops = &smb_ops;
> +	com = ultrasoc_register_com(parent, &com_descp);

Why is this needed?  As far as I can see this device does not need to
register with the ultrasoc core.

To me the very first thing do to about this patchset is to move this in
drivers/hwtracing/coresight/.  That will dissociate this code completely from
the ultrasoc core (more on that later) and avoid duplications as pointed out by
Suzuki.

There are several things to address with this patch but there is no point in
elaborating further until the above hasn't been done.

> +	if (IS_ERR(com)) {
> +		dev_err(dev, "Failed to register smb com.\n");
> +		return PTR_ERR(com);
> +	}
> +
> +	drvdata->com = com;
> +	return 0;
> +}
> +
> +static int smb_probe(struct platform_device *pdev)
> +{
> +	struct smb_drv_data *drvdata;
> +	int ret;
> +
> +	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	ret = smb_init_res(pdev, drvdata);
> +	if (ret)
> +		return ret;
> +
> +	smb_set_default_hw(drvdata);
> +	spin_lock_init(&drvdata->spinlock);
> +	drvdata->dev = &pdev->dev;
> +	drvdata->pid = -1;
> +
> +	ret = smb_config_com_descp(pdev, drvdata);
> +	if (ret)
> +		return ret;
> +
> +	ret = smb_register_sink(pdev, drvdata);
> +	if (ret) {
> +		dev_err(&pdev->dev, "failed to register smb sink.\n");
> +		ultrasoc_unregister_com(drvdata->com);
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, drvdata);
> +	return 0;
> +}
> +
> +static int smb_remove(struct platform_device *pdev)
> +{
> +	struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
> +
> +	smb_unregister_sink(drvdata);
> +	ultrasoc_unregister_com(drvdata->com);
> +	smb_release_data_buffer(drvdata);
> +	return 0;
> +}
> +
> +static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
> +	{"HISI03A1", },
> +	{},
> +};
> +
> +static struct platform_driver smb_driver = {
> +	.driver = {
> +		.name = "ultrasoc,smb",
> +		.acpi_match_table = ultrasoc_smb_acpi_match,
> +	},
> +	.probe = smb_probe,
> +	.remove = smb_remove,
> +};
> +module_platform_driver(smb_driver);
> +
> +MODULE_DESCRIPTION("Ultrasoc smb driver");
> +MODULE_LICENSE("Dual MIT/GPL");
> +MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
> +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-smb.h b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
> new file mode 100644
> index 0000000..e37d510
> --- /dev/null
> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
> @@ -0,0 +1,182 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
> + * charge, to any person obtaining a copy of this software and associated
> + * documentation files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use, copy, modify,
> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
> + * and to permit persons to whom the Software is furnished to do so, subject
> + * to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Code herein communicates with and accesses proprietary hardware which is
> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
> + * Software Ltd.
> + *
> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
> + * their intellectual property. This paragraph may not be removed or modified
> + * in any way without permission from Siemens Digital Industries Software Ltd.
> + */
> +
> +#ifndef _ULTRASOC_SMB_H
> +#define _ULTRASOC_SMB_H
> +
> +#include <linux/coresight.h>
> +#include <linux/list.h>
> +#include <linux/miscdevice.h>
> +
> +#include "ultrasoc.h"
> +
> +#define SMB_GLOBAL_CFG		0X0
> +#define SMB_GLOBAL_EN		0X4
> +#define SMB_GLOBAL_INT		0X8
> +#define SMB_LB_CFG_LO		0X40
> +#define SMB_LB_CFG_HI		0X44
> +#define SMB_LB_INT_CTRL		0X48
> +#define SMB_LB_INT_STS		0X4C
> +#define SMB_LB_BASE_LO		0X50
> +#define SMB_LB_BASE_HI		0X54
> +#define SMB_LB_LIMIT		0X58
> +#define SMB_LB_RD_ADDR		0X5C
> +#define SMB_LB_WR_ADDR		0X60
> +#define SMB_LB_PURGE		0X64
> +
> +#define SMB_MSG_LC(lc)		((lc & 0x3) << 2)
> +#define SMB_BST_LEN(len)	(((len - 1) & 0xff) << 4)
> +/* idle message injection timer period */
> +#define SMB_IDLE_PRD(period)	(((period - 216) & 0xf) << 12)
> +#define SMB_MEM_WR(credit, rate) (((credit & 0x3) << 16) | ((rate & 0xf) << 18))
> +#define SMB_MEM_RD(credit, rate) (((credit & 0x3) << 22) | ((rate & 0xf) << 24))
> +#define HISI_SMB_GLOBAL_CFG                                                    \
> +	(SMB_MSG_LC(0) | SMB_IDLE_PRD(231) | SMB_MEM_WR(0x3, 0x0) |            \
> +	 SMB_MEM_RD(0x3, 0x6) | SMB_BST_LEN(16))
> +
> +#define SMB_INT_ENABLE		BIT(0)
> +#define SMB_INT_TYPE_PULSE	BIT(1)
> +#define SMB_INT_POLARITY_HIGH	BIT(2)
> +#define HISI_SMB_GLB_INT_CFG	(SMB_INT_ENABLE | SMB_INT_TYPE_PULSE |         \
> +				SMB_INT_POLARITY_HIGH)
> +
> +/* logic buffer config register low 32b */
> +#define SMB_BUF_ENABLE			BIT(0)
> +#define SMB_BUF_SINGLE_END		BIT(1)
> +#define SMB_BUF_INIT			BIT(8)
> +#define SMB_BUF_CONTINUOUS		BIT(11)
> +#define SMB_FLOW_MASK			GENMASK(19, 16)
> +#define SMB_BUF_CFG_STREAMING						       \
> +	(SMB_BUF_INIT | SMB_BUF_CONTINUOUS | SMB_FLOW_MASK)
> +#define SMB_BUF_WRITE_BASE		GENMASK(31, 0)
> +
> +/* logic buffer config register high 32b */
> +#define SMB_MSG_FILTER(lower, upper)	((lower & 0xff) | ((upper & 0xff) << 8))
> +#define SMB_BUF_INT_ENABLE		BIT(0)
> +#define SMB_BUF_NOTE_NOT_EMPTY		BIT(8)
> +#define SMB_BUF_NOTE_BLOCK_AVAIL	BIT(9)
> +#define SMB_BUF_NOTE_TRIGGERED		BIT(10)
> +#define SMB_BUF_NOTE_FULL		BIT(11)
> +#define HISI_SMB_BUF_INT_CFG						\
> +	(SMB_BUF_INT_ENABLE | SMB_BUF_NOTE_NOT_EMPTY |			\
> +	   SMB_BUF_NOTE_BLOCK_AVAIL | SMB_BUF_NOTE_TRIGGERED |		\
> +	    SMB_BUF_NOTE_FULL)
> +
> +struct smb_data_buffer {
> +	/* memory buffer for hardware write */
> +	u32 buf_cfg_mode;
> +	bool lost;
> +	void __iomem *buf_base;
> +	u64 buf_base_phys;
> +	u64 buf_size;
> +	u64 to_copy;
> +	u32 rd_offset;
> +};
> +
> +struct smb_drv_data {
> +	void __iomem *base;
> +	struct device *dev;
> +	struct ultrasoc_com *com;
> +	struct smb_data_buffer smb_db;
> +	/* to register ultrasoc smb as a coresight sink device. */
> +	struct coresight_device	*csdev;
> +	spinlock_t		spinlock;
> +	local_t			reading;
> +	pid_t			pid;
> +	u32			mode;
> +	struct miscdevice miscdev;
> +};
> +
> +#define SMB_MSG_ALIGH_SIZE 0x400
> +
> +static inline struct smb_data_buffer *
> +	dev_get_smb_data_buffer(struct device *dev)
> +{
> +	struct smb_drv_data *drvdata = dev_get_drvdata(dev);
> +
> +	if (drvdata)
> +		return &drvdata->smb_db;
> +
> +	return NULL;
> +}
> +
> +/*
> + * Coresight doesn't export the following
> + * structures(cs_mode,cs_buffers,etm_event_data),
> + * so we redefine a copy here.
> + */
> +enum cs_mode {
> +	CS_MODE_DISABLED,
> +	CS_MODE_SYSFS,
> +	CS_MODE_PERF,
> +};
> +
> +struct cs_buffers {
> +	unsigned int		cur;
> +	unsigned int		nr_pages;
> +	unsigned long		offset;
> +	local_t			data_size;
> +	bool			snapshot;
> +	void			**data_pages;
> +};
> +
> +struct etm_event_data {
> +	struct work_struct work;
> +	cpumask_t mask;
> +	void *snk_config;
> +	struct list_head * __percpu *path;
> +};
> +
> +#if IS_ENABLED(CONFIG_CORESIGHT)
> +int etm_perf_symlink(struct coresight_device *csdev, bool link);
> +int etm_perf_add_symlink_sink(struct coresight_device *csdev);
> +void etm_perf_del_symlink_sink(struct coresight_device *csdev);
> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
> +{
> +	struct etm_event_data *data = perf_get_aux(handle);
> +
> +	if (data)
> +		return data->snk_config;
> +	return NULL;
> +}
> +#else
> +static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
> +{ return -EINVAL; }
> +int etm_perf_add_symlink_sink(struct coresight_device *csdev)
> +{ return -EINVAL; }
> +void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
> +{
> +	return NULL;
> +}
> +
> +#endif /* CONFIG_CORESIGHT */
> +
> +#endif
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver
  2021-06-15  9:34 ` [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver Qi Liu
  2021-06-16 23:23   ` kernel test robot
@ 2021-06-29 21:22   ` Mathieu Poirier
  2021-07-08  9:27     ` liuqi (BA)
  1 sibling, 1 reply; 16+ messages in thread
From: Mathieu Poirier @ 2021-06-29 21:22 UTC (permalink / raw)
  To: Qi Liu
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight, linuxarm

On Tue, Jun 15, 2021 at 05:34:43PM +0800, Qi Liu wrote:
> This patch adds driver for ultrasoc AXI Communicator. It includes
> a platform driver to probe AXI Communicator device, a set of
> operations to access the service data, and a service work entry
> which will be called by the standard communicator service.
> 
> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
> Signed-off-by: Qi Liu <liuqi115@huawei.com>
> ---
>  drivers/hwtracing/ultrasoc/Kconfig            |   9 +
>  drivers/hwtracing/ultrasoc/Makefile           |   3 +
>  drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c | 334 ++++++++++++++++++++++++++
>  drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h |  66 +++++
>  4 files changed, 412 insertions(+)
>  create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
>  create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
> 
> diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
> index 90a3934..77429f3 100644
> --- a/drivers/hwtracing/ultrasoc/Kconfig
> +++ b/drivers/hwtracing/ultrasoc/Kconfig
> @@ -13,4 +13,13 @@ menuconfig ULTRASOC
>  	  specification and configure the right series of components when a
>  	  trace source gets enabled.
>  
> +if ULTRASOC
> +config ULTRASOC_AXI_COM
> +	tristate "Ultrasoc AXI communicator drivers"
> +	help
> +	  This config enables support for Ultrasoc AXI Bus Communicator
> +	  drivers. The AXI Communicator has upstream and downstream channels,
> +	  the upstream channel is used to transmit user configuration, and
> +	  downstream channel to carry response and trace data to the users.
> +
>  endif
> diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
> index a747171..54711a7b 100644
> --- a/drivers/hwtracing/ultrasoc/Makefile
> +++ b/drivers/hwtracing/ultrasoc/Makefile
> @@ -5,3 +5,6 @@
>  
>  obj-$(CONFIG_ULTRASOC) += ultrasoc-drv.o
>  ultrasoc-drv-objs := ultrasoc.o
> +
> +obj-$(CONFIG_ULTRASOC_AXI_COM) += ultrasoc-axi-com-drv.o
> +ultrasoc-axi-com-drv-objs := ultrasoc-axi-com.o
> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
> new file mode 100644
> index 0000000..af153dd
> --- /dev/null
> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.c
> @@ -0,0 +1,334 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
> + * charge, to any person obtaining a copy of this software and associated
> + * documentation files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use, copy, modify,
> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
> + * and to permit persons to whom the Software is furnished to do so, subject
> + * to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Code herein communicates with and accesses proprietary hardware which is
> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
> + * Software Ltd.
> + *
> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
> + * their intellectual property. This paragraph may not be removed or modified
> + * in any way without permission from Siemens Digital Industries Software Ltd.
> + */
> +#include <linux/acpi.h>
> +#include <linux/err.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <asm/unaligned.h>
> +
> +#include "ultrasoc-axi-com.h"
> +
> +static void axi_com_enable_hw(struct axi_com_drv_data *drvdata)
> +{
> +	u32 val;
> +
> +	val = readl(drvdata->base + AXIC_US_CTL);
> +	val |= AXIC_US_CTL_EN;
> +	writel(val, drvdata->base + AXIC_US_CTL);
> +
> +	val = readl(drvdata->base + AXIC_DS_CTL);
> +	val |= AXIC_DS_CTL_EN;
> +	writel(val, drvdata->base + AXIC_DS_CTL);
> +}
> +
> +static void axi_com_disable_hw(struct axi_com_drv_data *drvdata)
> +{
> +	u32 val;
> +
> +	val = readl(drvdata->base + AXIC_US_CTL);
> +	val &= ~AXIC_US_CTL_EN;
> +	writel(val, drvdata->base + AXIC_US_CTL);
> +
> +	val = readl(drvdata->base + AXIC_DS_CTL);
> +	val &= ~AXIC_DS_CTL_EN;
> +	writel(val, drvdata->base + AXIC_DS_CTL);
> +}
> +
> +static inline bool axi_com_us_buf_full(struct axi_com_drv_data *drvdata)
> +{
> +	return readl(drvdata->base + AXIC_US_BUF_STS) & BIT(0);
> +}
> +
> +static inline bool axi_com_ds_buf_full(struct axi_com_drv_data *drvdata)
> +{
> +	return readl(drvdata->base + AXIC_DS_BUF_STS) & BIT(0);
> +}
> +
> +static int axi_com_try_send_msg(struct axi_com_drv_data *drvdata)
> +{
> +	struct msg_descp *msg;
> +	struct list_head *node;
> +	int index = 0;
> +	int unsent;
> +	u32 data;
> +
> +	if (axi_com_us_buf_full(drvdata)) {
> +		dev_err_once(drvdata->dev, "No room for upstream buffer.\n");
> +		return US_SERVICE_IDLE;
> +	}
> +
> +	spin_lock(&drvdata->us_msg_list_lock);
> +	if (list_empty(&drvdata->us_msg_head)) {
> +		spin_unlock(&drvdata->us_msg_list_lock);
> +		return US_SERVICE_IDLE;
> +	}
> +
> +	node = drvdata->us_msg_head.next;
> +	list_del(node);
> +	drvdata->us_msg_cur--;
> +	msg = container_of(node, struct msg_descp, node);
> +	spin_unlock(&drvdata->us_msg_list_lock);
> +
> +	unsent = msg->msg_len;
> +	dev_dbg(drvdata->dev, "Length of send msg: %d.\n", msg->msg_len);
> +	while (unsent > 0) {
> +		data = get_unaligned_le32(&msg->msg_buf[index++]);
> +		writel(data, drvdata->base + AXIC_US_DATA);

Who reads the data that gets written here?

> +		unsent -= AXIC_MSG_LEN_PER_SEND;
> +	}
> +	kfree(msg);
> +
> +	return US_SERVICE_ONWORK;
> +}
> +
> +static int axi_com_try_recv_msg(struct axi_com_drv_data *drvdata)
> +{
> +	struct msg_descp tmp_msg = {0};
> +	struct msg_descp *msg;
> +	bool lost = false;
> +	u32 index = 0;
> +	u32 status, entries, data;
> +
> +	if (!axi_com_ds_buf_full(drvdata))
> +		return US_SERVICE_IDLE;
> +
> +	msg = kzalloc(sizeof(*msg), GFP_KERNEL);
> +	if (!msg) {
> +		/*
> +		 * create local variable tmp_msg to read and clear
> +		 * the downstream message.
> +		 */
> +		msg = &tmp_msg;
> +		lost = true;
> +	}
> +
> +	do {
> +		if (index == USMSG_MAX_IDX) {
> +			dev_warn(drvdata->dev, "Illegal message.\n");
> +			break;
> +		}
> +		data = readl(drvdata->base + AXIC_DS_DATA);

Same thing - who writes the data that gets read here?  

> +		put_unaligned_le32(data, &msg->msg_buf[index++]);
> +		status = readl(drvdata->base + AXIC_DS_RD_STS);
> +		entries = status & GENMASK(7, 4);
> +		msg->msg_len += AXIC_MSG_LEN_PER_REC;
> +	} while (entries != 0);
> +
> +	if (!lost) {
> +		spin_lock(&drvdata->ds_msg_list_lock);
> +		drvdata->ds_msg_cur++;
> +		drvdata->ds_msg_counter++;
> +		list_add_tail(&msg->node, &drvdata->ds_msg_head);
> +		spin_unlock(&drvdata->ds_msg_list_lock);
> +	}
> +
> +	return US_SERVICE_ONWORK;
> +}
> +
> +static int axi_com_work(struct ultrasoc_com *uscom)
> +{
> +	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
> +	int us_ds_flag;
> +
> +	us_ds_flag = axi_com_try_recv_msg(drvdata);
> +	us_ds_flag |= axi_com_try_send_msg(drvdata);

Why does this work has to be done in ultrasoc.c when (as far as I can see) it
could be done as part of this driver using something like
smp_call_function_single()?

> +
> +	return us_ds_flag;
> +}
> +
> +static ssize_t axi_com_show_status(struct ultrasoc_com *uscom, char *buf,
> +				   ssize_t wr_size)
> +{
> +	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
> +
> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %d\n",
> +				 "ds msg list num", drvdata->ds_msg_cur);
> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %d\n",
> +				 "us msg list num", drvdata->us_msg_cur);

Same comment as smb.

> +
> +	return wr_size;
> +}
> +
> +static void axi_com_put_raw_msg(struct ultrasoc_com *uscom, int msg_size,
> +			unsigned long long msg_data)
> +{
> +	struct axi_com_drv_data *drvdata = ultrasoc_com_get_drvdata(uscom);
> +	struct msg_descp *p_msg;
> +
> +	p_msg = kmalloc(sizeof(*p_msg), GFP_KERNEL);
> +	if (!p_msg)
> +		return;
> +
> +	p_msg->msg_len = msg_size;
> +	put_unaligned_le64(msg_data, &p_msg->msg_buf[0]);
> +	spin_lock(&drvdata->us_msg_list_lock);
> +	list_add_tail(&p_msg->node, &drvdata->us_msg_head);
> +	drvdata->us_msg_cur++;
> +	spin_unlock(&drvdata->us_msg_list_lock);
> +
> +	if (uscom->service_status != ULTRASOC_COM_SERVICE_STOPPED)
> +		wake_up_process(uscom->service);
> +	else
> +		dev_warn(uscom->dev, "Com service is not running.\n");
> +}
> +
> +static struct uscom_ops axi_com_ops = {
> +	.com_status = axi_com_show_status,
> +	.put_raw_msg = axi_com_put_raw_msg,
> +};
> +
> +/*
> + * Config hardwares on the tracing path, using DSM calls to avoid exposing
> + * hardware message format.
> + */
> +static int axi_com_config_inport(struct axi_com_drv_data *drvdata, bool enable)
> +{
> +	struct device *dev = drvdata->dev;
> +	u32 flag = enable ? 1 : 0;
> +	union acpi_object *obj;
> +	guid_t guid;
> +
> +	if (guid_parse("82ae1283-7f6a-4cbe-aa06-53e8fb24db18", &guid)) {
> +		dev_err(dev, "Get GUID failed.\n");
> +		return -EINVAL;
> +	}
> +
> +	obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &guid, 0, flag, NULL);
> +	if (!obj)
> +		dev_err(dev, "ACPI handle failed!\n");
> +
> +	ACPI_FREE(obj);
> +
> +	return 0;
> +}
> +
> +static int axi_com_config_com_descp(struct platform_device *pdev,
> +				    struct axi_com_drv_data *drvdata)
> +{
> +	struct device *parent = pdev->dev.parent;
> +	struct ultrasoc_com_descp com_descp = {0};
> +	struct device *dev = &pdev->dev;
> +	struct ultrasoc_com *com;
> +
> +	com_descp.name = pdev->name;
> +	com_descp.com_type = ULTRASOC_COM_TYPE_BOTH;

Both what?  From this I have to guess there is a dual purpose to this specific
type but there is no documentation as to what that can be.  This set is
difficult to review because of the general lack of documention.

> +	com_descp.com_dev = dev;
> +	com_descp.uscom_ops = &axi_com_ops;
> +	com_descp.com_work = axi_com_work;
> +
> +	if (device_property_read_u64(dev, "ultrasoc,default_route",
> +				     &com_descp.default_route_msg)) {
> +		dev_err(dev, "Failed to read default_route!\n");
> +		return -EINVAL;
> +	}
> +
> +	com = ultrasoc_register_com(parent, &com_descp);
> +	if (IS_ERR(com)) {
> +		dev_err(dev, "Failed to register to ultrasoc.\n");
> +		return PTR_ERR(com);
> +	}
> +
> +	/*
> +	 * record the returned com point in drvdata,
> +	 * it will be used to unregister the com
> +	 * from ultrasoc.
> +	 */
> +	drvdata->com = com;
> +	return 0;
> +}
> +
> +static int axi_com_probe(struct platform_device *pdev)
> +{
> +	struct axi_com_drv_data *drvdata;
> +	int ret;
> +
> +	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
> +	if (!drvdata)
> +		return -ENOMEM;
> +
> +	drvdata->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(drvdata->base)) {
> +		dev_err(&pdev->dev, "Failed to ioremap resource.\n");
> +		return PTR_ERR(drvdata->base);
> +	}
> +
> +	drvdata->dev = &pdev->dev;
> +	spin_lock_init(&drvdata->ds_msg_list_lock);
> +	spin_lock_init(&drvdata->us_msg_list_lock);
> +	INIT_LIST_HEAD(&drvdata->us_msg_head);
> +	INIT_LIST_HEAD(&drvdata->ds_msg_head);
> +
> +	axi_com_enable_hw(drvdata);
> +	ret = axi_com_config_inport(drvdata, true);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, drvdata);
> +	return axi_com_config_com_descp(pdev, drvdata);
> +}
> +
> +static int axi_com_remove(struct platform_device *pdev)
> +{
> +	struct axi_com_drv_data *drvdata = platform_get_drvdata(pdev);
> +	int ret;
> +
> +	if (ultrasoc_unregister_com(drvdata->com) == -EBUSY)
> +		return -EBUSY;
> +
> +	ret = axi_com_config_inport(drvdata, false);
> +	if (ret)
> +		return ret;
> +
> +	axi_com_disable_hw(drvdata);
> +	usmsg_list_realse_all(&drvdata->ds_msg_head);
> +	usmsg_list_realse_all(&drvdata->us_msg_head);
> +
> +	return 0;
> +}
> +
> +static const struct acpi_device_id ultrasoc_axi_com_acpi_match[] = {
> +	{"HISI03B1", },
> +	{},
> +};

No need for MODULE_DEVICE_TABLE()?

I am very confused as to what this IP does...  And I'm even more confused as to
why ultrasoc.c is needed at all.  As I pointed out in a previous comment there
is a lot of work to do on this patchset but there is no point in writing more
while questions about the current design choices are pending.

I am done reviewing this set.

Thanks,
Mathieu

> +
> +static struct platform_driver axi_com_driver = {
> +	.driver = {
> +		.name = "ultrasoc,axi-com",
> +		.acpi_match_table = ultrasoc_axi_com_acpi_match,
> +	},
> +	.probe = axi_com_probe,
> +	.remove = axi_com_remove,
> +};
> +module_platform_driver(axi_com_driver);
> +
> +MODULE_DESCRIPTION("Ultrasoc AXI COM driver");
> +MODULE_LICENSE("Dual MIT/GPL");
> +MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
> +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
> new file mode 100644
> index 0000000..64bcf83
> --- /dev/null
> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
> @@ -0,0 +1,66 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
> + * charge, to any person obtaining a copy of this software and associated
> + * documentation files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use, copy, modify,
> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
> + * and to permit persons to whom the Software is furnished to do so, subject
> + * to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Code herein communicates with and accesses proprietary hardware which is
> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
> + * Software Ltd.
> + *
> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
> + * their intellectual property. This paragraph may not be removed or modified
> + * in any way without permission from Siemens Digital Industries Software Ltd.
> + */
> +#ifndef ULTRASOC_AXI_COM_H
> +#define ULTRASOC_AXI_COM_H
> +
> +#include "ultrasoc.h"
> +
> +#define AXIC_US_CTL 0X0 /* Upstream general control */
> +#define AXIC_US_DATA 0XC /* Upstream message data */
> +#define AXIC_US_BUF_STS 0X10 /* Upstream buffer status */
> +
> +#define AXIC_DS_CTL 0X80 /* Downstream general contral */
> +#define AXIC_DS_DATA 0X8C /* Downstream message data */
> +#define AXIC_DS_BUF_STS 0X90 /* Downstream buffer status */
> +#define AXIC_DS_RD_STS 0X94 /* Downstream read status */
> +
> +#define AXIC_MSG_LEN_PER_SEND		4
> +#define AXIC_MSG_LEN_PER_REC		4
> +#define AXIC_US_CTL_EN 0x1
> +#define AXIC_DS_CTL_EN 0x1
> +
> +struct axi_com_drv_data {
> +	void __iomem *base;
> +
> +	struct device *dev;
> +	struct ultrasoc_com *com;
> +
> +	u32 ds_msg_counter;
> +
> +	u32 us_msg_cur;
> +	spinlock_t us_msg_list_lock;
> +	struct list_head us_msg_head;
> +
> +	u32 ds_msg_cur;
> +	spinlock_t ds_msg_list_lock;
> +	struct list_head ds_msg_head;
> +};
> +
> +#endif
> -- 
> 2.7.4
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-24 22:47   ` Suzuki K Poulose
@ 2021-07-08  8:25     ` liuqi (BA)
  0 siblings, 0 replies; 16+ messages in thread
From: liuqi (BA) @ 2021-07-08  8:25 UTC (permalink / raw)
  To: Suzuki K Poulose, Linuxarm, alexander.shishkin, mathieu.poirier,
	jonathan.zhouwen, f.fangjian
  Cc: linux-kernel, coresight


Hi Suzuki,
On 2021/6/25 6:47, Suzuki K Poulose wrote:
> Hi Qi
> 
> On 15/06/2021 10:34, Qi Liu wrote:
>> This patch adds driver for System Memory Buffer. It includes
>> a platform driver for the SMB device.
>>
>> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> ---
>>   drivers/hwtracing/ultrasoc/Kconfig        |   9 +
>>   drivers/hwtracing/ultrasoc/Makefile       |   3 +
>>   drivers/hwtracing/ultrasoc/ultrasoc-smb.c | 663 
>> ++++++++++++++++++++++++++++++
>>   drivers/hwtracing/ultrasoc/ultrasoc-smb.h | 182 ++++++++
>>   4 files changed, 857 insertions(+)
>>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
>>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h
>>
> 
>> +/*
>> + * Coresight doesn't export the following
>> + * structures(cs_mode,cs_buffers,etm_event_data),
>> + * so we redefine a copy here.
>> + */
> 
> Please do not duplicate them. This indicates, either :
> 
>   - You need to place your driver under coresight
> 
>   OR
> 
>   - Export the required definitions.
> 

got it, I'll move this driver to coresight/ultrasoc, thanks.

Qi
>> +enum cs_mode {
>> +    CS_MODE_DISABLED,
>> +    CS_MODE_SYSFS,
>> +    CS_MODE_PERF,
>> +};
>> +
> 
>> +struct cs_buffers {
>> +    unsigned int        cur;
>> +    unsigned int        nr_pages;
>> +    unsigned long        offset;
>> +    local_t            data_size;
>> +    bool            snapshot;
>> +    void            **data_pages;
>> +};
>> +
> 
> Why does this need to be replicated ?
> 
>> +struct etm_event_data {
>> +    struct work_struct work;
>> +    cpumask_t mask;
>> +    void *snk_config;
>> +    struct list_head * __percpu *path;
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_CORESIGHT)
>> +int etm_perf_symlink(struct coresight_device *csdev, bool link);
>> +int etm_perf_add_symlink_sink(struct coresight_device *csdev);
>> +void etm_perf_del_symlink_sink(struct coresight_device *csdev);
>> +static inline void *etm_perf_sink_config(struct perf_output_handle 
>> *handle)
>> +{
>> +    struct etm_event_data *data = perf_get_aux(handle);
>> +
>> +    if (data)
>> +        return data->snk_config;
>> +    return NULL;
>> +}
>> +#else
>> +static inline int etm_perf_symlink(struct coresight_device *csdev, 
>> bool link)
>> +{ return -EINVAL; }
>> +int etm_perf_add_symlink_sink(struct coresight_device *csdev)
>> +{ return -EINVAL; }
>> +void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
>> +static inline void *etm_perf_sink_config(struct perf_output_handle 
>> *handle)
>> +{
>> +    return NULL;
>> +}
>> +
>> +#endif /* CONFIG_CORESIGHT */
>> +
>> +#endif
>>
> 
> Suzuki
> .


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver
  2021-06-29 20:50   ` Mathieu Poirier
@ 2021-07-08  8:47     ` liuqi (BA)
  0 siblings, 0 replies; 16+ messages in thread
From: liuqi (BA) @ 2021-07-08  8:47 UTC (permalink / raw)
  To: Mathieu Poirier, Linuxarm
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight


Hi Mathieu,

Thanks for reviewing this patch.

On 2021/6/30 4:50, Mathieu Poirier wrote:
> Hi Qi,
> 
> On Tue, Jun 15, 2021 at 05:34:44PM +0800, Qi Liu wrote:
>> This patch adds driver for System Memory Buffer. It includes
>> a platform driver for the SMB device.
>>
>> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> ---
>>   drivers/hwtracing/ultrasoc/Kconfig        |   9 +
>>   drivers/hwtracing/ultrasoc/Makefile       |   3 +
>>   drivers/hwtracing/ultrasoc/ultrasoc-smb.c | 663 ++++++++++++++++++++++++++++++
>>   drivers/hwtracing/ultrasoc/ultrasoc-smb.h | 182 ++++++++
>>   4 files changed, 857 insertions(+)
>>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.c
>>   create mode 100644 drivers/hwtracing/ultrasoc/ultrasoc-smb.h
>>
>> diff --git a/drivers/hwtracing/ultrasoc/Kconfig b/drivers/hwtracing/ultrasoc/Kconfig
>> index 77429f3..8899949 100644
>> --- a/drivers/hwtracing/ultrasoc/Kconfig
>> +++ b/drivers/hwtracing/ultrasoc/Kconfig
>> @@ -22,4 +22,13 @@ config ULTRASOC_AXI_COM
>>   	  the upstream channel is used to transmit user configuration, and
>>   	  downstream channel to carry response and trace data to the users.
>>   
>> +config ULTRASOC_SMB
>> +	tristate "Ultrasoc System memory buffer drivers"
>> +	help
>> +	  This config enables support for Ultrasoc System Memory Buffer
>> +	  drivers. The System Memory Buffer provides a way to buffer and
>> +	  store messages in system memory. It provides a capability to
>> +	  store messages received on its input message interface to an
>> +	  area of system memory.
>> +
>>   endif
>> diff --git a/drivers/hwtracing/ultrasoc/Makefile b/drivers/hwtracing/ultrasoc/Makefile
>> index 54711a7b..b174ca8 100644
>> --- a/drivers/hwtracing/ultrasoc/Makefile
>> +++ b/drivers/hwtracing/ultrasoc/Makefile
>> @@ -8,3 +8,6 @@ ultrasoc-drv-objs := ultrasoc.o
>>   
>>   obj-$(CONFIG_ULTRASOC_AXI_COM) += ultrasoc-axi-com-drv.o
>>   ultrasoc-axi-com-drv-objs := ultrasoc-axi-com.o
>> +

[...]

>> +static ssize_t smb_show_status(struct ultrasoc_com *com, char *buf,
>> +			       ssize_t wr_size)
>> +{
>> +	struct smb_drv_data *drvdata;
>> +	u32 value;
>> +
>> +	drvdata = dev_get_drvdata(com->dev);
>> +	value = readl(drvdata->base + SMB_LB_INT_STS);
>> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: 0x%08x\n",
>> +				 "interrupt status", value);
>> +	value = readl(drvdata->base + SMB_LB_WR_ADDR);
>> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "write point",
>> +				 value);
>> +	value = readl(drvdata->base + SMB_LB_RD_ADDR);
>> +	wr_size += sysfs_emit_at(buf, wr_size, "%-20s: %#x\n", "read point",
>> +				 value);
> 
> This will not work.  The sysfs interface requires one line per entry.  Please
> look at what other coresight drivers do in that area.

got it, I'll use multi sysfs files to show these information, like this:
static struct attribute *smb_sink_attrs[] = {
	&dev_attr_read_pos.attr,
	&dev_attr_write_pos.attr,
	&dev_attr_buf_status.attr,
	NULL,
};
> 
>> +
>> +	return wr_size;
>> +}
>> +
>> +static int smb_init_data_buffer(struct platform_device *pdev,
>> +				struct smb_data_buffer *sdb)
>> +{
>> +	struct resource *res;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +	if (IS_ERR(res)) {
>> +		dev_err(&pdev->dev, "SMB device without data buffer.\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	sdb->buf_base_phys = res->start;
>> +	sdb->buf_size = resource_size(res);
>> +	if (sdb->buf_size == 0)
>> +		return -EINVAL;
>> +
>> +	sdb->buf_base = ioremap_cache(sdb->buf_base_phys, sdb->buf_size);
> 
> Why no using devm_ioremap_resource() ?
will use this, thanks.

> 
>> +	if (sdb->buf_base == NULL)
>> +		return -ENOMEM;
>> +
>> +	sdb->buf_cfg_mode = SMB_BUF_CFG_STREAMING;
> 
> As far as I can tell there is no point in keeping the value of
> SMB_BUF_CFG_STREAMING in the smb_data_buffer since it isn't used for anything
> else other than setting a HW register in smb_set_default_hw().
> 
thanks, will remove this member in struct smb_data_buffer, thanks.

>> +	return 0;
>> +}
>> +

[...]

>> +static int smb_config_com_descp(struct platform_device *pdev,
>> +				struct smb_drv_data *drvdata)
>> +{
>> +	struct device *parent = pdev->dev.parent;
>> +	struct ultrasoc_com_descp com_descp = {0};
>> +	struct device *dev = &pdev->dev;
>> +	struct ultrasoc_com *com;
>> +
>> +	com_descp.name = pdev->name;
>> +	com_descp.com_type = ULTRASOC_COM_TYPE_DOWN;
>> +	com_descp.com_dev = dev;
>> +	com_descp.uscom_ops = &smb_ops;
>> +	com = ultrasoc_register_com(parent, &com_descp);
> 
> Why is this needed?  As far as I can see this device does not need to
> register with the ultrasoc core.
> 
yes, you are right.

At the beginning we use the ultrasoc core to adapt multiple hardware 
devices and support more capabilities. But after discussing with 
Siemens, we are allowed to only upstream the axi-com and smb driver.

So the software architecture seems unreasonable now, I'll refactor it in 
next version, thanks.

> To me the very first thing do to about this patchset is to move this in
> drivers/hwtracing/coresight/.  That will dissociate this code completely from
> the ultrasoc core (more on that later) and avoid duplications as pointed out by
> Suzuki.
> 
> There are several things to address with this patch but there is no point in
> elaborating further until the above hasn't been done.
> 
Got it, will move the driver next time, thanks.

Qi
>> +	if (IS_ERR(com)) {
>> +		dev_err(dev, "Failed to register smb com.\n");
>> +		return PTR_ERR(com);
>> +	}
>> +
>> +	drvdata->com = com;
>> +	return 0;
>> +}
>> +
>> +static int smb_probe(struct platform_device *pdev)
>> +{
>> +	struct smb_drv_data *drvdata;
>> +	int ret;
>> +
>> +	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
>> +	if (!drvdata)
>> +		return -ENOMEM;
>> +
>> +	ret = smb_init_res(pdev, drvdata);
>> +	if (ret)
>> +		return ret;
>> +
>> +	smb_set_default_hw(drvdata);
>> +	spin_lock_init(&drvdata->spinlock);
>> +	drvdata->dev = &pdev->dev;
>> +	drvdata->pid = -1;
>> +
>> +	ret = smb_config_com_descp(pdev, drvdata);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = smb_register_sink(pdev, drvdata);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "failed to register smb sink.\n");
>> +		ultrasoc_unregister_com(drvdata->com);
>> +		return ret;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, drvdata);
>> +	return 0;
>> +}
>> +
>> +static int smb_remove(struct platform_device *pdev)
>> +{
>> +	struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
>> +
>> +	smb_unregister_sink(drvdata);
>> +	ultrasoc_unregister_com(drvdata->com);
>> +	smb_release_data_buffer(drvdata);
>> +	return 0;
>> +}
>> +
>> +static const struct acpi_device_id ultrasoc_smb_acpi_match[] = {
>> +	{"HISI03A1", },
>> +	{},
>> +};
>> +
>> +static struct platform_driver smb_driver = {
>> +	.driver = {
>> +		.name = "ultrasoc,smb",
>> +		.acpi_match_table = ultrasoc_smb_acpi_match,
>> +	},
>> +	.probe = smb_probe,
>> +	.remove = smb_remove,
>> +};
>> +module_platform_driver(smb_driver);
>> +
>> +MODULE_DESCRIPTION("Ultrasoc smb driver");
>> +MODULE_LICENSE("Dual MIT/GPL");
>> +MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
>> +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
>> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-smb.h b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
>> new file mode 100644
>> index 0000000..e37d510
>> --- /dev/null
>> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-smb.h
>> @@ -0,0 +1,182 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
>> + * charge, to any person obtaining a copy of this software and associated
>> + * documentation files (the "Software"), to deal in the Software without
>> + * restriction, including without limitation the rights to use, copy, modify,
>> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
>> + * and to permit persons to whom the Software is furnished to do so, subject
>> + * to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + * Code herein communicates with and accesses proprietary hardware which is
>> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
>> + * Software Ltd.
>> + *
>> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
>> + * their intellectual property. This paragraph may not be removed or modified
>> + * in any way without permission from Siemens Digital Industries Software Ltd.
>> + */
>> +
>> +#ifndef _ULTRASOC_SMB_H
>> +#define _ULTRASOC_SMB_H
>> +
>> +#include <linux/coresight.h>
>> +#include <linux/list.h>
>> +#include <linux/miscdevice.h>
>> +
>> +#include "ultrasoc.h"
>> +
>> +#define SMB_GLOBAL_CFG		0X0
>> +#define SMB_GLOBAL_EN		0X4
>> +#define SMB_GLOBAL_INT		0X8
>> +#define SMB_LB_CFG_LO		0X40
>> +#define SMB_LB_CFG_HI		0X44
>> +#define SMB_LB_INT_CTRL		0X48
>> +#define SMB_LB_INT_STS		0X4C
>> +#define SMB_LB_BASE_LO		0X50
>> +#define SMB_LB_BASE_HI		0X54
>> +#define SMB_LB_LIMIT		0X58
>> +#define SMB_LB_RD_ADDR		0X5C
>> +#define SMB_LB_WR_ADDR		0X60
>> +#define SMB_LB_PURGE		0X64
>> +
>> +#define SMB_MSG_LC(lc)		((lc & 0x3) << 2)
>> +#define SMB_BST_LEN(len)	(((len - 1) & 0xff) << 4)
>> +/* idle message injection timer period */
>> +#define SMB_IDLE_PRD(period)	(((period - 216) & 0xf) << 12)
>> +#define SMB_MEM_WR(credit, rate) (((credit & 0x3) << 16) | ((rate & 0xf) << 18))
>> +#define SMB_MEM_RD(credit, rate) (((credit & 0x3) << 22) | ((rate & 0xf) << 24))
>> +#define HISI_SMB_GLOBAL_CFG                                                    \
>> +	(SMB_MSG_LC(0) | SMB_IDLE_PRD(231) | SMB_MEM_WR(0x3, 0x0) |            \
>> +	 SMB_MEM_RD(0x3, 0x6) | SMB_BST_LEN(16))
>> +
>> +#define SMB_INT_ENABLE		BIT(0)
>> +#define SMB_INT_TYPE_PULSE	BIT(1)
>> +#define SMB_INT_POLARITY_HIGH	BIT(2)
>> +#define HISI_SMB_GLB_INT_CFG	(SMB_INT_ENABLE | SMB_INT_TYPE_PULSE |         \
>> +				SMB_INT_POLARITY_HIGH)
>> +
>> +/* logic buffer config register low 32b */
>> +#define SMB_BUF_ENABLE			BIT(0)
>> +#define SMB_BUF_SINGLE_END		BIT(1)
>> +#define SMB_BUF_INIT			BIT(8)
>> +#define SMB_BUF_CONTINUOUS		BIT(11)
>> +#define SMB_FLOW_MASK			GENMASK(19, 16)
>> +#define SMB_BUF_CFG_STREAMING						       \
>> +	(SMB_BUF_INIT | SMB_BUF_CONTINUOUS | SMB_FLOW_MASK)
>> +#define SMB_BUF_WRITE_BASE		GENMASK(31, 0)
>> +
>> +/* logic buffer config register high 32b */
>> +#define SMB_MSG_FILTER(lower, upper)	((lower & 0xff) | ((upper & 0xff) << 8))
>> +#define SMB_BUF_INT_ENABLE		BIT(0)
>> +#define SMB_BUF_NOTE_NOT_EMPTY		BIT(8)
>> +#define SMB_BUF_NOTE_BLOCK_AVAIL	BIT(9)
>> +#define SMB_BUF_NOTE_TRIGGERED		BIT(10)
>> +#define SMB_BUF_NOTE_FULL		BIT(11)
>> +#define HISI_SMB_BUF_INT_CFG						\
>> +	(SMB_BUF_INT_ENABLE | SMB_BUF_NOTE_NOT_EMPTY |			\
>> +	   SMB_BUF_NOTE_BLOCK_AVAIL | SMB_BUF_NOTE_TRIGGERED |		\
>> +	    SMB_BUF_NOTE_FULL)
>> +
>> +struct smb_data_buffer {
>> +	/* memory buffer for hardware write */
>> +	u32 buf_cfg_mode;
>> +	bool lost;
>> +	void __iomem *buf_base;
>> +	u64 buf_base_phys;
>> +	u64 buf_size;
>> +	u64 to_copy;
>> +	u32 rd_offset;
>> +};
>> +
>> +struct smb_drv_data {
>> +	void __iomem *base;
>> +	struct device *dev;
>> +	struct ultrasoc_com *com;
>> +	struct smb_data_buffer smb_db;
>> +	/* to register ultrasoc smb as a coresight sink device. */
>> +	struct coresight_device	*csdev;
>> +	spinlock_t		spinlock;
>> +	local_t			reading;
>> +	pid_t			pid;
>> +	u32			mode;
>> +	struct miscdevice miscdev;
>> +};
>> +
>> +#define SMB_MSG_ALIGH_SIZE 0x400
>> +
>> +static inline struct smb_data_buffer *
>> +	dev_get_smb_data_buffer(struct device *dev)
>> +{
>> +	struct smb_drv_data *drvdata = dev_get_drvdata(dev);
>> +
>> +	if (drvdata)
>> +		return &drvdata->smb_db;
>> +
>> +	return NULL;
>> +}
>> +
>> +/*
>> + * Coresight doesn't export the following
>> + * structures(cs_mode,cs_buffers,etm_event_data),
>> + * so we redefine a copy here.
>> + */
>> +enum cs_mode {
>> +	CS_MODE_DISABLED,
>> +	CS_MODE_SYSFS,
>> +	CS_MODE_PERF,
>> +};
>> +
>> +struct cs_buffers {
>> +	unsigned int		cur;
>> +	unsigned int		nr_pages;
>> +	unsigned long		offset;
>> +	local_t			data_size;
>> +	bool			snapshot;
>> +	void			**data_pages;
>> +};
>> +
>> +struct etm_event_data {
>> +	struct work_struct work;
>> +	cpumask_t mask;
>> +	void *snk_config;
>> +	struct list_head * __percpu *path;
>> +};
>> +
>> +#if IS_ENABLED(CONFIG_CORESIGHT)
>> +int etm_perf_symlink(struct coresight_device *csdev, bool link);
>> +int etm_perf_add_symlink_sink(struct coresight_device *csdev);
>> +void etm_perf_del_symlink_sink(struct coresight_device *csdev);
>> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
>> +{
>> +	struct etm_event_data *data = perf_get_aux(handle);
>> +
>> +	if (data)
>> +		return data->snk_config;
>> +	return NULL;
>> +}
>> +#else
>> +static inline int etm_perf_symlink(struct coresight_device *csdev, bool link)
>> +{ return -EINVAL; }
>> +int etm_perf_add_symlink_sink(struct coresight_device *csdev)
>> +{ return -EINVAL; }
>> +void etm_perf_del_symlink_sink(struct coresight_device *csdev) {}
>> +static inline void *etm_perf_sink_config(struct perf_output_handle *handle)
>> +{
>> +	return NULL;
>> +}
>> +
>> +#endif /* CONFIG_CORESIGHT */
>> +
>> +#endif
>> -- 
>> 2.7.4
>>
> .
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver
  2021-06-29 21:22   ` Mathieu Poirier
@ 2021-07-08  9:27     ` liuqi (BA)
  0 siblings, 0 replies; 16+ messages in thread
From: liuqi (BA) @ 2021-07-08  9:27 UTC (permalink / raw)
  To: Mathieu Poirier, Linuxarm
  Cc: alexander.shishkin, suzuki.poulose, jonathan.zhouwen, f.fangjian,
	linux-kernel, coresight


Hi Mathieu,

On 2021/6/30 5:22, Mathieu Poirier wrote:
> On Tue, Jun 15, 2021 at 05:34:43PM +0800, Qi Liu wrote:
>> This patch adds driver for ultrasoc AXI Communicator. It includes
>> a platform driver to probe AXI Communicator device, a set of
>> operations to access the service data, and a service work entry
>> which will be called by the standard communicator service.
>>
>> Signed-off-by: Jonathan Zhou <jonathan.zhouwen@huawei.com>
>> Signed-off-by: Qi Liu <liuqi115@huawei.com>
>> ---

[...]

>> +
>> +static const struct acpi_device_id ultrasoc_axi_com_acpi_match[] = {
>> +	{"HISI03B1", },
>> +	{},
>> +};
> 
> No need for MODULE_DEVICE_TABLE()?
> 
> I am very confused as to what this IP does...  And I'm even more confused as to
> why ultrasoc.c is needed at all.  As I pointed out in a previous comment there
> is a lot of work to do on this patchset but there is no point in writing more
> while questions about the current design choices are pending.
> thanks for reviewing this patch.

This module is used on Hip08 platform, to store trace data from ETM, you 
can find the data path diagram in kernel document patch.

And this module is developed by Ultrasoc technology, which is acquired 
by Siemens, we still use "Ultrasoc" to name document and structures.

At the beginning we use the ultrasoc.c as a framework to adapt multiple 
hardware devices and support more capabilities. But after discussing 
with suppliers, we are only allowed to upstream the axi-com and smb driver.

So the software architecture seems unreasonable now, I'll refactor it in 
next version, thanks.

Qi
> I am done reviewing this set.
> 
> Thanks,
> Mathieu
> 
>> +
>> +static struct platform_driver axi_com_driver = {
>> +	.driver = {
>> +		.name = "ultrasoc,axi-com",
>> +		.acpi_match_table = ultrasoc_axi_com_acpi_match,
>> +	},
>> +	.probe = axi_com_probe,
>> +	.remove = axi_com_remove,
>> +};
>> +module_platform_driver(axi_com_driver);
>> +
>> +MODULE_DESCRIPTION("Ultrasoc AXI COM driver");
>> +MODULE_LICENSE("Dual MIT/GPL");
>> +MODULE_AUTHOR("Jonathan Zhou <jonathan.zhouwen@huawei.com>");
>> +MODULE_AUTHOR("Qi Liu <liuqi115@huawei.com>");
>> diff --git a/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
>> new file mode 100644
>> index 0000000..64bcf83
>> --- /dev/null
>> +++ b/drivers/hwtracing/ultrasoc/ultrasoc-axi-com.h
>> @@ -0,0 +1,66 @@
>> +/* SPDX-License-Identifier: MIT */
>> +/*
>> + * Copyright (C) 2021 Hisilicon Limited Permission is hereby granted, free of
>> + * charge, to any person obtaining a copy of this software and associated
>> + * documentation files (the "Software"), to deal in the Software without
>> + * restriction, including without limitation the rights to use, copy, modify,
>> + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
>> + * and to permit persons to whom the Software is furnished to do so, subject
>> + * to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
>> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + * Code herein communicates with and accesses proprietary hardware which is
>> + * licensed intellectual property (IP) belonging to Siemens Digital Industries
>> + * Software Ltd.
>> + *
>> + * Siemens Digital Industries Software Ltd. asserts and reserves all rights to
>> + * their intellectual property. This paragraph may not be removed or modified
>> + * in any way without permission from Siemens Digital Industries Software Ltd.
>> + */
>> +#ifndef ULTRASOC_AXI_COM_H
>> +#define ULTRASOC_AXI_COM_H
>> +
>> +#include "ultrasoc.h"
>> +
>> +#define AXIC_US_CTL 0X0 /* Upstream general control */
>> +#define AXIC_US_DATA 0XC /* Upstream message data */
>> +#define AXIC_US_BUF_STS 0X10 /* Upstream buffer status */
>> +
>> +#define AXIC_DS_CTL 0X80 /* Downstream general contral */
>> +#define AXIC_DS_DATA 0X8C /* Downstream message data */
>> +#define AXIC_DS_BUF_STS 0X90 /* Downstream buffer status */
>> +#define AXIC_DS_RD_STS 0X94 /* Downstream read status */
>> +
>> +#define AXIC_MSG_LEN_PER_SEND		4
>> +#define AXIC_MSG_LEN_PER_REC		4
>> +#define AXIC_US_CTL_EN 0x1
>> +#define AXIC_DS_CTL_EN 0x1
>> +
>> +struct axi_com_drv_data {
>> +	void __iomem *base;
>> +
>> +	struct device *dev;
>> +	struct ultrasoc_com *com;
>> +
>> +	u32 ds_msg_counter;
>> +
>> +	u32 us_msg_cur;
>> +	spinlock_t us_msg_list_lock;
>> +	struct list_head us_msg_head;
>> +
>> +	u32 ds_msg_cur;
>> +	spinlock_t ds_msg_list_lock;
>> +	struct list_head ds_msg_head;
>> +};
>> +
>> +#endif
>> -- 
>> 2.7.4
>>
> .
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-07-08  9:27 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-15  9:34 [RFC PATCH 0/4] Add support for Ultrasoc Trace Module Qi Liu
2021-06-15  9:34 ` [RFC PATCH 1/4] Documentation: tracing: Documentation for ultrasoc framework and drivers Qi Liu
2021-06-23 22:51   ` Mathieu Poirier
2021-06-24 12:43     ` liuqi (BA)
2021-06-24 16:26       ` Mathieu Poirier
2021-06-15  9:34 ` [RFC PATCH 2/4] ultrasoc: add ultrasoc core layer framework Qi Liu
2021-06-15  9:34 ` [RFC PATCH 3/4] ultrasoc: Add ultrasoc AXI Communicator driver Qi Liu
2021-06-16 23:23   ` kernel test robot
2021-06-29 21:22   ` Mathieu Poirier
2021-07-08  9:27     ` liuqi (BA)
2021-06-15  9:34 ` [RFC PATCH 4/4] ultrasoc: Add System Memory Buffer driver Qi Liu
2021-06-16 18:04   ` kernel test robot
2021-06-24 22:47   ` Suzuki K Poulose
2021-07-08  8:25     ` liuqi (BA)
2021-06-29 20:50   ` Mathieu Poirier
2021-07-08  8:47     ` liuqi (BA)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.