[PATCH v2] stm: class: Add MIPI OST protocol support

From: Mao Jinlong
Date: Wed Apr 19 2023 - 10:15:48 EST


Add MIPI OST(Open System Trace) protocol support for stm to format
the traces. OST over STP packet consists of Header/Payload/End. In
header, there will be STARTSIMPLE/VERSION/ENTITY/PROTOCOL. STARTSIMPLE
is used to signal the beginning of a simplified OST base protocol
packet.The Entity ID field is a one byte unsigned number that identifies
the source. FLAG packet is used for END token.

Signed-off-by: Tingwei Zhang <quic_tingweiz@xxxxxxxxxxx>
Signed-off-by: Yuanfang Zhang <quic_yuanfang@xxxxxxxxxxx>
Signed-off-by: Mao Jinlong <quic_jinlmao@xxxxxxxxxxx>
---
.../ABI/testing/configfs-stp-policy-p_ost | 13 ++
Documentation/trace/p_ost.rst | 40 ++++
drivers/hwtracing/stm/Kconfig | 14 ++
drivers/hwtracing/stm/Makefile | 2 +
drivers/hwtracing/stm/p_ost.c | 213 ++++++++++++++++++
5 files changed, 282 insertions(+)
create mode 100644 Documentation/ABI/testing/configfs-stp-policy-p_ost
create mode 100644 Documentation/trace/p_ost.rst
create mode 100644 drivers/hwtracing/stm/p_ost.c

diff --git a/Documentation/ABI/testing/configfs-stp-policy-p_ost b/Documentation/ABI/testing/configfs-stp-policy-p_ost
new file mode 100644
index 000000000000..7ad11ae21760
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-stp-policy-p_ost
@@ -0,0 +1,13 @@
+What: /config/stp-policy/<device>:p_ost.<policy>/<node>/entity_available
+Date: April 2023
+KernelVersion: 6.3
+Description:
+ Show entity that p_ost supports, RO.
+
+What: /config/stp-policy/<device>:p_ost.<policy>/<node>/entity
+Date: April 2023
+KernelVersion: 6.3
+Description:
+ Set the entity which is to identify the source, RW.
+ The available entity can be gotten by reading entity_available.
+
diff --git a/Documentation/trace/p_ost.rst b/Documentation/trace/p_ost.rst
new file mode 100644
index 000000000000..8d7afa341b9e
--- /dev/null
+++ b/Documentation/trace/p_ost.rst
@@ -0,0 +1,40 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================
+MIPI OST over STP
+===================
+
+The OST(Open System Trace) driver is used with STM class devices to
+generate standardized trace stream. Trace sources can be identified
+by different entity ids.
+
+CONFIG_STM_PROTO_OST is for p_ost driver enablement. Once this config
+is enabled, you can select the p_ost protocol by command below:
+
+# mkdir /sys/kernel/config/stp-policy/stm0:p_ost.policy
+
+The policy name format is extended like this:
+ <device_name>:<protocol_name>.<policy_name>
+
+With coresight-stm device, it will be look like "stm0:p_ost.policy".
+
+You can check if the protocol is set successfully by:
+# cat /sys/kernel/config/stp-policy/stm0:p_ost.policy/protocol
+p_ost
+
+With MIPI OST protocol driver, the attributes for each protocol node is:
+# mkdir /sys/kernel/config/stp-policy/stm0:p_ost.policy/default
+# ls /sys/kernel/config/stp-policy/stm0:p_ost.policy/default
+channels entity masters
+
+The entity here is the set the entity that p_ost supports. Currently
+p_ost supports ftrace and console entity.
+
+Get current available entity that p_ost supports:
+# cat /sys/kernel/config/stp-policy/stm0:p_ost.policy/default/entity_available
+ftrace console
+
+Set entity:
+# echo 'ftrace' > /sys/kernel/config/stp-policy/stm0:p_ost.policy/default/entity
+
+See Documentation/ABI/testing/configfs-stp-policy-p_ost for more details.
diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig
index eda6b11d40a1..daa4aa09f64d 100644
--- a/drivers/hwtracing/stm/Kconfig
+++ b/drivers/hwtracing/stm/Kconfig
@@ -40,6 +40,20 @@ config STM_PROTO_SYS_T

If you don't know what this is, say N.

+config STM_PROTO_OST
+ tristate "MIPI OST STM framing protocol driver"
+ default CONFIG_STM
+ help
+ This is an implementation of MIPI OST protocol to be used
+ over the STP transport. In addition to the data payload, it
+ also carries additional metadata for entity, better
+ means of trace source identification, etc.
+
+ The receiving side must be able to decode this protocol in
+ addition to the MIPI STP, in order to extract the data.
+
+ If you don't know what this is, say N.
+
config STM_DUMMY
tristate "Dummy STM driver"
help
diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile
index 1692fcd29277..715fc721891e 100644
--- a/drivers/hwtracing/stm/Makefile
+++ b/drivers/hwtracing/stm/Makefile
@@ -5,9 +5,11 @@ stm_core-y := core.o policy.o

obj-$(CONFIG_STM_PROTO_BASIC) += stm_p_basic.o
obj-$(CONFIG_STM_PROTO_SYS_T) += stm_p_sys-t.o
+obj-$(CONFIG_STM_PROTO_OST) += stm_p_ost.o

stm_p_basic-y := p_basic.o
stm_p_sys-t-y := p_sys-t.o
+stm_p_ost-y := p_ost.o

obj-$(CONFIG_STM_DUMMY) += dummy_stm.o

diff --git a/drivers/hwtracing/stm/p_ost.c b/drivers/hwtracing/stm/p_ost.c
new file mode 100644
index 000000000000..fe99b68569d3
--- /dev/null
+++ b/drivers/hwtracing/stm/p_ost.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * MIPI OST framing protocol for STM devices.
+ */
+
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/stm.h>
+#include "stm.h"
+
+
+#define OST_TOKEN_STARTSIMPLE (0x10)
+#define OST_VERSION_MIPI1 (0x10 << 8)
+
+/* entity id to identify the source*/
+#define OST_ENTITY_FTRACE (0x01 << 16)
+#define OST_ENTITY_CONSOLE (0x02 << 16)
+
+#define OST_CONTROL_PROTOCOL (0x0 << 24)
+
+/*
+ * OST Base Protocol Header
+ *
+ * Position Bits Field Name
+ * 0 8 STARTSIMPLE
+ * 1 8 Version
+ * 2 8 Entity ID
+ * 3 8 protocol ID
+ */
+#define DATA_HEADER (OST_TOKEN_STARTSIMPLE | OST_VERSION_MIPI1 | \
+ OST_CONTROL_PROTOCOL)
+
+#define STM_MAKE_VERSION(ma, mi) ((ma << 8) | mi)
+#define STM_HEADER_MAGIC (0x5953)
+
+enum ost_entity_type {
+ OST_ENTITY_TYPE_NONE,
+ OST_ENTITY_TYPE_FTRACE,
+ OST_ENTITY_TYPE_CONSOLE,
+};
+
+static const char * const str_ost_entity_type[] = {
+ [OST_ENTITY_TYPE_NONE] = "none",
+ [OST_ENTITY_TYPE_FTRACE] = "ftrace",
+ [OST_ENTITY_TYPE_CONSOLE] = "console",
+};
+
+struct ost_policy_node {
+ enum ost_entity_type entity_type;
+};
+
+struct ost_output {
+ struct ost_policy_node node;
+};
+
+/* Set default entity type as none */
+static void ost_policy_node_init(void *priv)
+{
+ struct ost_policy_node *pn = priv;
+
+ pn->entity_type = OST_ENTITY_TYPE_NONE;
+}
+
+static int ost_output_open(void *priv, struct stm_output *output)
+{
+ struct ost_policy_node *pn = priv;
+ struct ost_output *opriv;
+
+ opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC);
+ if (!opriv)
+ return -ENOMEM;
+
+ memcpy(&opriv->node, pn, sizeof(opriv->node));
+ output->pdrv_private = opriv;
+ return 0;
+}
+
+static void ost_output_close(struct stm_output *output)
+{
+ kfree(output->pdrv_private);
+}
+
+static ssize_t ost_t_policy_entity_show(struct config_item *item,
+ char *page)
+{
+ struct ost_policy_node *pn = to_pdrv_policy_node(item);
+
+ return scnprintf(page, PAGE_SIZE, "%s\n",
+ str_ost_entity_type[pn->entity_type]);
+}
+
+static ssize_t
+ost_t_policy_entity_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
+ struct ost_policy_node *pn = to_pdrv_policy_node(item);
+ char str[10] = "";
+
+ mutex_lock(mutexp);
+ if (sscanf(page, "%s", str) != 1)
+ return -EINVAL;
+ mutex_unlock(mutexp);
+
+ if (!strcmp(str, str_ost_entity_type[OST_ENTITY_TYPE_FTRACE]))
+ pn->entity_type = OST_ENTITY_TYPE_FTRACE;
+ else if (!strcmp(str, str_ost_entity_type[OST_ENTITY_TYPE_CONSOLE]))
+ pn->entity_type = OST_ENTITY_TYPE_CONSOLE;
+ else
+ return -EINVAL;
+ return count;
+}
+CONFIGFS_ATTR(ost_t_policy_, entity);
+
+static ssize_t ost_t_policy_entity_available_show(struct config_item *item,
+ char *page)
+{
+ return scnprintf(page, PAGE_SIZE, "%s\n", "ftrace console");
+}
+CONFIGFS_ATTR_RO(ost_t_policy_, entity_available);
+
+static struct configfs_attribute *ost_t_policy_attrs[] = {
+ &ost_t_policy_attr_entity,
+ &ost_t_policy_attr_entity_available,
+ NULL,
+};
+
+static ssize_t notrace ost_write(struct stm_data *data,
+ struct stm_output *output, unsigned int chan,
+ const char *buf, size_t count)
+{
+ unsigned int c = output->channel + chan;
+ unsigned int m = output->master;
+ const unsigned char nil = 0;
+ u32 header = DATA_HEADER;
+ u8 trc_hdr[16];
+ ssize_t sz;
+
+ struct ost_output *op = output->pdrv_private;
+
+ /*
+ * Identify the source by entity type.
+ * If entity type is not set, return error value.
+ */
+ if (op->node.entity_type == OST_ENTITY_TYPE_FTRACE) {
+ header |= OST_ENTITY_FTRACE;
+ } else if (op->node.entity_type == OST_ENTITY_TYPE_CONSOLE) {
+ header |= OST_ENTITY_CONSOLE;
+ } else {
+ pr_debug("p_ost: Entity must be set for trace data.");
+ return -EINVAL;
+ }
+
+ /*
+ * STP framing rules for OST frames:
+ * * the first packet of the OST frame is marked;
+ * * the last packet is a FLAG with timestamped tag.
+ */
+ /* Message layout: HEADER / DATA / TAIL */
+ /* HEADER */
+ sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_MARKED,
+ 4, (u8 *)&header);
+ if (sz <= 0)
+ return sz;
+
+ /* DATA */
+ *(u16 *)(trc_hdr) = STM_MAKE_VERSION(0, 4);
+ *(u16 *)(trc_hdr + 2) = STM_HEADER_MAGIC;
+ *(u32 *)(trc_hdr + 4) = raw_smp_processor_id();
+ *(u64 *)(trc_hdr + 8) = task_tgid_nr(get_current());
+ sz = stm_data_write(data, m, c, false, trc_hdr, sizeof(trc_hdr));
+ if (sz <= 0)
+ return sz;
+
+ sz = stm_data_write(data, m, c, false, buf, count);
+
+ /* TAIL */
+ if (sz > 0)
+ data->packet(data, m, c, STP_PACKET_FLAG,
+ STP_PACKET_TIMESTAMPED, 0, &nil);
+
+ return sz;
+}
+
+static const struct stm_protocol_driver ost_pdrv = {
+ .owner = THIS_MODULE,
+ .name = "p_ost",
+ .write = ost_write,
+ .policy_attr = ost_t_policy_attrs,
+ .output_open = ost_output_open,
+ .output_close = ost_output_close,
+ .policy_node_init = ost_policy_node_init,
+};
+
+static int ost_stm_init(void)
+{
+ return stm_register_protocol(&ost_pdrv);
+}
+
+static void ost_stm_exit(void)
+{
+ stm_unregister_protocol(&ost_pdrv);
+}
+
+module_init(ost_stm_init);
+module_exit(ost_stm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MIPI Open System Trace STM framing protocol driver");
--
2.17.1