xref: /openbmc/linux/drivers/hwtracing/stm/p_sys-t.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
1d69d5e83SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
2d69d5e83SAlexander Shishkin /*
3d69d5e83SAlexander Shishkin  * MIPI SyS-T framing protocol for STM devices.
4d69d5e83SAlexander Shishkin  * Copyright (c) 2018, Intel Corporation.
5d69d5e83SAlexander Shishkin  */
6d69d5e83SAlexander Shishkin 
7d69d5e83SAlexander Shishkin #include <linux/configfs.h>
8d69d5e83SAlexander Shishkin #include <linux/module.h>
9d69d5e83SAlexander Shishkin #include <linux/device.h>
10d69d5e83SAlexander Shishkin #include <linux/slab.h>
11d69d5e83SAlexander Shishkin #include <linux/uuid.h>
12d69d5e83SAlexander Shishkin #include <linux/stm.h>
13d69d5e83SAlexander Shishkin #include "stm.h"
14d69d5e83SAlexander Shishkin 
15d69d5e83SAlexander Shishkin enum sys_t_message_type {
16d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_BUILD	= 0,
17d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_SHORT32,
18d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_STRING,
19d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_CATALOG,
20d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_RAW	= 6,
21d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_SHORT64,
22d69d5e83SAlexander Shishkin 	MIPI_SYST_TYPE_CLOCK,
23d69d5e83SAlexander Shishkin };
24d69d5e83SAlexander Shishkin 
25d69d5e83SAlexander Shishkin enum sys_t_message_severity {
26d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_MAX	= 0,
27d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_FATAL,
28d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_ERROR,
29d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_WARNING,
30d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_INFO,
31d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_USER1,
32d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_USER2,
33d69d5e83SAlexander Shishkin 	MIPI_SYST_SEVERITY_DEBUG,
34d69d5e83SAlexander Shishkin };
35d69d5e83SAlexander Shishkin 
36d69d5e83SAlexander Shishkin enum sys_t_message_build_subtype {
37d69d5e83SAlexander Shishkin 	MIPI_SYST_BUILD_ID_COMPACT32 = 0,
38d69d5e83SAlexander Shishkin 	MIPI_SYST_BUILD_ID_COMPACT64,
39d69d5e83SAlexander Shishkin 	MIPI_SYST_BUILD_ID_LONG,
40d69d5e83SAlexander Shishkin };
41d69d5e83SAlexander Shishkin 
42d69d5e83SAlexander Shishkin enum sys_t_message_clock_subtype {
43d69d5e83SAlexander Shishkin 	MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1,
44d69d5e83SAlexander Shishkin };
45d69d5e83SAlexander Shishkin 
46d69d5e83SAlexander Shishkin enum sys_t_message_string_subtype {
47d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_GENERIC	= 1,
48d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_FUNCTIONENTER,
49d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_FUNCTIONEXIT,
50d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_INVALIDPARAM	= 5,
51d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_ASSERT		= 7,
52d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_PRINTF_32	= 11,
53d69d5e83SAlexander Shishkin 	MIPI_SYST_STRING_PRINTF_64	= 12,
54d69d5e83SAlexander Shishkin };
55d69d5e83SAlexander Shishkin 
56d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPE(t)		((u32)(MIPI_SYST_TYPE_ ## t))
57d69d5e83SAlexander Shishkin #define MIPI_SYST_SEVERITY(s)		((u32)(MIPI_SYST_SEVERITY_ ## s) << 4)
58d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LOC		BIT(8)
59d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LEN		BIT(9)
60d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_CHK		BIT(10)
61d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_TS		BIT(11)
62d69d5e83SAlexander Shishkin #define MIPI_SYST_UNIT(u)		((u32)(u) << 12)
63d69d5e83SAlexander Shishkin #define MIPI_SYST_ORIGIN(o)		((u32)(o) << 16)
64d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_GUID		BIT(23)
65d69d5e83SAlexander Shishkin #define MIPI_SYST_SUBTYPE(s)		((u32)(MIPI_SYST_ ## s) << 24)
66d69d5e83SAlexander Shishkin #define MIPI_SYST_UNITLARGE(u)		(MIPI_SYST_UNIT(u & 0xf) | \
67d69d5e83SAlexander Shishkin 					 MIPI_SYST_ORIGIN(u >> 4))
68d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPES(t, s)		(MIPI_SYST_TYPE(t) | \
69d69d5e83SAlexander Shishkin 					 MIPI_SYST_SUBTYPE(t ## _ ## s))
70d69d5e83SAlexander Shishkin 
71d69d5e83SAlexander Shishkin #define DATA_HEADER	(MIPI_SYST_TYPES(STRING, GENERIC)	| \
72d69d5e83SAlexander Shishkin 			 MIPI_SYST_SEVERITY(INFO)		| \
73d69d5e83SAlexander Shishkin 			 MIPI_SYST_OPT_GUID)
74d69d5e83SAlexander Shishkin 
7539f10239SAlexander Shishkin #define CLOCK_SYNC_HEADER	(MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC)	| \
7639f10239SAlexander Shishkin 				 MIPI_SYST_SEVERITY(MAX))
7739f10239SAlexander Shishkin 
78d69d5e83SAlexander Shishkin struct sys_t_policy_node {
79d69d5e83SAlexander Shishkin 	uuid_t		uuid;
80d69d5e83SAlexander Shishkin 	bool		do_len;
81d69d5e83SAlexander Shishkin 	unsigned long	ts_interval;
8239f10239SAlexander Shishkin 	unsigned long	clocksync_interval;
83d69d5e83SAlexander Shishkin };
84d69d5e83SAlexander Shishkin 
85d69d5e83SAlexander Shishkin struct sys_t_output {
86d69d5e83SAlexander Shishkin 	struct sys_t_policy_node	node;
87d69d5e83SAlexander Shishkin 	unsigned long	ts_jiffies;
8839f10239SAlexander Shishkin 	unsigned long	clocksync_jiffies;
89d69d5e83SAlexander Shishkin };
90d69d5e83SAlexander Shishkin 
sys_t_policy_node_init(void * priv)91d69d5e83SAlexander Shishkin static void sys_t_policy_node_init(void *priv)
92d69d5e83SAlexander Shishkin {
93d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = priv;
94d69d5e83SAlexander Shishkin 
95*41c9f7fbSAndy Shevchenko 	uuid_gen(&pn->uuid);
96d69d5e83SAlexander Shishkin }
97d69d5e83SAlexander Shishkin 
sys_t_output_open(void * priv,struct stm_output * output)98d69d5e83SAlexander Shishkin static int sys_t_output_open(void *priv, struct stm_output *output)
99d69d5e83SAlexander Shishkin {
100d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = priv;
101d69d5e83SAlexander Shishkin 	struct sys_t_output *opriv;
102d69d5e83SAlexander Shishkin 
103d69d5e83SAlexander Shishkin 	opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC);
104d69d5e83SAlexander Shishkin 	if (!opriv)
105d69d5e83SAlexander Shishkin 		return -ENOMEM;
106d69d5e83SAlexander Shishkin 
107d69d5e83SAlexander Shishkin 	memcpy(&opriv->node, pn, sizeof(opriv->node));
108d69d5e83SAlexander Shishkin 	output->pdrv_private = opriv;
109d69d5e83SAlexander Shishkin 
110d69d5e83SAlexander Shishkin 	return 0;
111d69d5e83SAlexander Shishkin }
112d69d5e83SAlexander Shishkin 
sys_t_output_close(struct stm_output * output)113d69d5e83SAlexander Shishkin static void sys_t_output_close(struct stm_output *output)
114d69d5e83SAlexander Shishkin {
115d69d5e83SAlexander Shishkin 	kfree(output->pdrv_private);
116d69d5e83SAlexander Shishkin }
117d69d5e83SAlexander Shishkin 
sys_t_policy_uuid_show(struct config_item * item,char * page)118d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_uuid_show(struct config_item *item,
119d69d5e83SAlexander Shishkin 				      char *page)
120d69d5e83SAlexander Shishkin {
121d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
122d69d5e83SAlexander Shishkin 
123d69d5e83SAlexander Shishkin 	return sprintf(page, "%pU\n", &pn->uuid);
124d69d5e83SAlexander Shishkin }
125d69d5e83SAlexander Shishkin 
126d69d5e83SAlexander Shishkin static ssize_t
sys_t_policy_uuid_store(struct config_item * item,const char * page,size_t count)127d69d5e83SAlexander Shishkin sys_t_policy_uuid_store(struct config_item *item, const char *page,
128d69d5e83SAlexander Shishkin 			size_t count)
129d69d5e83SAlexander Shishkin {
130d69d5e83SAlexander Shishkin 	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
131d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
132d69d5e83SAlexander Shishkin 	int ret;
133d69d5e83SAlexander Shishkin 
134d69d5e83SAlexander Shishkin 	mutex_lock(mutexp);
135d69d5e83SAlexander Shishkin 	ret = uuid_parse(page, &pn->uuid);
136d69d5e83SAlexander Shishkin 	mutex_unlock(mutexp);
137d69d5e83SAlexander Shishkin 
138d69d5e83SAlexander Shishkin 	return ret < 0 ? ret : count;
139d69d5e83SAlexander Shishkin }
140d69d5e83SAlexander Shishkin 
141d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, uuid);
142d69d5e83SAlexander Shishkin 
sys_t_policy_do_len_show(struct config_item * item,char * page)143d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_do_len_show(struct config_item *item,
144d69d5e83SAlexander Shishkin 				      char *page)
145d69d5e83SAlexander Shishkin {
146d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
147d69d5e83SAlexander Shishkin 
148d69d5e83SAlexander Shishkin 	return sprintf(page, "%d\n", pn->do_len);
149d69d5e83SAlexander Shishkin }
150d69d5e83SAlexander Shishkin 
151d69d5e83SAlexander Shishkin static ssize_t
sys_t_policy_do_len_store(struct config_item * item,const char * page,size_t count)152d69d5e83SAlexander Shishkin sys_t_policy_do_len_store(struct config_item *item, const char *page,
153d69d5e83SAlexander Shishkin 			size_t count)
154d69d5e83SAlexander Shishkin {
155d69d5e83SAlexander Shishkin 	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
156d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
157d69d5e83SAlexander Shishkin 	int ret;
158d69d5e83SAlexander Shishkin 
159d69d5e83SAlexander Shishkin 	mutex_lock(mutexp);
160d69d5e83SAlexander Shishkin 	ret = kstrtobool(page, &pn->do_len);
161d69d5e83SAlexander Shishkin 	mutex_unlock(mutexp);
162d69d5e83SAlexander Shishkin 
163d69d5e83SAlexander Shishkin 	return ret ? ret : count;
164d69d5e83SAlexander Shishkin }
165d69d5e83SAlexander Shishkin 
166d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, do_len);
167d69d5e83SAlexander Shishkin 
sys_t_policy_ts_interval_show(struct config_item * item,char * page)168d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_ts_interval_show(struct config_item *item,
169d69d5e83SAlexander Shishkin 					     char *page)
170d69d5e83SAlexander Shishkin {
171d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
172d69d5e83SAlexander Shishkin 
173d69d5e83SAlexander Shishkin 	return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval));
174d69d5e83SAlexander Shishkin }
175d69d5e83SAlexander Shishkin 
176d69d5e83SAlexander Shishkin static ssize_t
sys_t_policy_ts_interval_store(struct config_item * item,const char * page,size_t count)177d69d5e83SAlexander Shishkin sys_t_policy_ts_interval_store(struct config_item *item, const char *page,
178d69d5e83SAlexander Shishkin 			       size_t count)
179d69d5e83SAlexander Shishkin {
180d69d5e83SAlexander Shishkin 	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
181d69d5e83SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
182d69d5e83SAlexander Shishkin 	unsigned int ms;
183d69d5e83SAlexander Shishkin 	int ret;
184d69d5e83SAlexander Shishkin 
185d69d5e83SAlexander Shishkin 	mutex_lock(mutexp);
186d69d5e83SAlexander Shishkin 	ret = kstrtouint(page, 10, &ms);
187d69d5e83SAlexander Shishkin 	mutex_unlock(mutexp);
188d69d5e83SAlexander Shishkin 
189d69d5e83SAlexander Shishkin 	if (!ret) {
190d69d5e83SAlexander Shishkin 		pn->ts_interval = msecs_to_jiffies(ms);
191d69d5e83SAlexander Shishkin 		return count;
192d69d5e83SAlexander Shishkin 	}
193d69d5e83SAlexander Shishkin 
194d69d5e83SAlexander Shishkin 	return ret;
195d69d5e83SAlexander Shishkin }
196d69d5e83SAlexander Shishkin 
197d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, ts_interval);
198d69d5e83SAlexander Shishkin 
sys_t_policy_clocksync_interval_show(struct config_item * item,char * page)19939f10239SAlexander Shishkin static ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item,
20039f10239SAlexander Shishkin 						    char *page)
20139f10239SAlexander Shishkin {
20239f10239SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
20339f10239SAlexander Shishkin 
20439f10239SAlexander Shishkin 	return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval));
20539f10239SAlexander Shishkin }
20639f10239SAlexander Shishkin 
20739f10239SAlexander Shishkin static ssize_t
sys_t_policy_clocksync_interval_store(struct config_item * item,const char * page,size_t count)20839f10239SAlexander Shishkin sys_t_policy_clocksync_interval_store(struct config_item *item,
20939f10239SAlexander Shishkin 				      const char *page, size_t count)
21039f10239SAlexander Shishkin {
21139f10239SAlexander Shishkin 	struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
21239f10239SAlexander Shishkin 	struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
21339f10239SAlexander Shishkin 	unsigned int ms;
21439f10239SAlexander Shishkin 	int ret;
21539f10239SAlexander Shishkin 
21639f10239SAlexander Shishkin 	mutex_lock(mutexp);
21739f10239SAlexander Shishkin 	ret = kstrtouint(page, 10, &ms);
21839f10239SAlexander Shishkin 	mutex_unlock(mutexp);
21939f10239SAlexander Shishkin 
22039f10239SAlexander Shishkin 	if (!ret) {
22139f10239SAlexander Shishkin 		pn->clocksync_interval = msecs_to_jiffies(ms);
22239f10239SAlexander Shishkin 		return count;
22339f10239SAlexander Shishkin 	}
22439f10239SAlexander Shishkin 
22539f10239SAlexander Shishkin 	return ret;
22639f10239SAlexander Shishkin }
22739f10239SAlexander Shishkin 
22839f10239SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, clocksync_interval);
22939f10239SAlexander Shishkin 
230d69d5e83SAlexander Shishkin static struct configfs_attribute *sys_t_policy_attrs[] = {
231d69d5e83SAlexander Shishkin 	&sys_t_policy_attr_uuid,
232d69d5e83SAlexander Shishkin 	&sys_t_policy_attr_do_len,
233d69d5e83SAlexander Shishkin 	&sys_t_policy_attr_ts_interval,
23439f10239SAlexander Shishkin 	&sys_t_policy_attr_clocksync_interval,
235d69d5e83SAlexander Shishkin 	NULL,
236d69d5e83SAlexander Shishkin };
237d69d5e83SAlexander Shishkin 
sys_t_need_ts(struct sys_t_output * op)238d69d5e83SAlexander Shishkin static inline bool sys_t_need_ts(struct sys_t_output *op)
239d69d5e83SAlexander Shishkin {
240d69d5e83SAlexander Shishkin 	if (op->node.ts_interval &&
241283f87c0SAlexander Shishkin 	    time_after(jiffies, op->ts_jiffies + op->node.ts_interval)) {
242d69d5e83SAlexander Shishkin 		op->ts_jiffies = jiffies;
243d69d5e83SAlexander Shishkin 
244d69d5e83SAlexander Shishkin 		return true;
245d69d5e83SAlexander Shishkin 	}
246d69d5e83SAlexander Shishkin 
247d69d5e83SAlexander Shishkin 	return false;
248d69d5e83SAlexander Shishkin }
249d69d5e83SAlexander Shishkin 
sys_t_need_clock_sync(struct sys_t_output * op)25039f10239SAlexander Shishkin static bool sys_t_need_clock_sync(struct sys_t_output *op)
25139f10239SAlexander Shishkin {
25239f10239SAlexander Shishkin 	if (op->node.clocksync_interval &&
253283f87c0SAlexander Shishkin 	    time_after(jiffies,
254283f87c0SAlexander Shishkin 		       op->clocksync_jiffies + op->node.clocksync_interval)) {
25539f10239SAlexander Shishkin 		op->clocksync_jiffies = jiffies;
25639f10239SAlexander Shishkin 
25739f10239SAlexander Shishkin 		return true;
25839f10239SAlexander Shishkin 	}
25939f10239SAlexander Shishkin 
26039f10239SAlexander Shishkin 	return false;
26139f10239SAlexander Shishkin }
26239f10239SAlexander Shishkin 
26339f10239SAlexander Shishkin static ssize_t
sys_t_clock_sync(struct stm_data * data,unsigned int m,unsigned int c)26439f10239SAlexander Shishkin sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c)
26539f10239SAlexander Shishkin {
26639f10239SAlexander Shishkin 	u32 header = CLOCK_SYNC_HEADER;
26739f10239SAlexander Shishkin 	const unsigned char nil = 0;
26839f10239SAlexander Shishkin 	u64 payload[2]; /* Clock value and frequency */
26939f10239SAlexander Shishkin 	ssize_t sz;
27039f10239SAlexander Shishkin 
27139f10239SAlexander Shishkin 	sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
27239f10239SAlexander Shishkin 			  4, (u8 *)&header);
27339f10239SAlexander Shishkin 	if (sz <= 0)
27439f10239SAlexander Shishkin 		return sz;
27539f10239SAlexander Shishkin 
27639f10239SAlexander Shishkin 	payload[0] = ktime_get_real_ns();
27739f10239SAlexander Shishkin 	payload[1] = NSEC_PER_SEC;
27839f10239SAlexander Shishkin 	sz = stm_data_write(data, m, c, false, &payload, sizeof(payload));
27939f10239SAlexander Shishkin 	if (sz <= 0)
28039f10239SAlexander Shishkin 		return sz;
28139f10239SAlexander Shishkin 
28239f10239SAlexander Shishkin 	data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
28339f10239SAlexander Shishkin 
28439f10239SAlexander Shishkin 	return sizeof(header) + sizeof(payload);
28539f10239SAlexander Shishkin }
28639f10239SAlexander Shishkin 
sys_t_write(struct stm_data * data,struct stm_output * output,unsigned int chan,const char * buf,size_t count)287d69d5e83SAlexander Shishkin static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output,
288d69d5e83SAlexander Shishkin 			   unsigned int chan, const char *buf, size_t count)
289d69d5e83SAlexander Shishkin {
290d69d5e83SAlexander Shishkin 	struct sys_t_output *op = output->pdrv_private;
291d69d5e83SAlexander Shishkin 	unsigned int c = output->channel + chan;
292d69d5e83SAlexander Shishkin 	unsigned int m = output->master;
293d69d5e83SAlexander Shishkin 	const unsigned char nil = 0;
294d69d5e83SAlexander Shishkin 	u32 header = DATA_HEADER;
295*41c9f7fbSAndy Shevchenko 	u8 uuid[UUID_SIZE];
296d69d5e83SAlexander Shishkin 	ssize_t sz;
297d69d5e83SAlexander Shishkin 
298d69d5e83SAlexander Shishkin 	/* We require an existing policy node to proceed */
299d69d5e83SAlexander Shishkin 	if (!op)
300d69d5e83SAlexander Shishkin 		return -EINVAL;
301d69d5e83SAlexander Shishkin 
30239f10239SAlexander Shishkin 	if (sys_t_need_clock_sync(op)) {
30339f10239SAlexander Shishkin 		sz = sys_t_clock_sync(data, m, c);
30439f10239SAlexander Shishkin 		if (sz <= 0)
30539f10239SAlexander Shishkin 			return sz;
30639f10239SAlexander Shishkin 	}
30739f10239SAlexander Shishkin 
308d69d5e83SAlexander Shishkin 	if (op->node.do_len)
309d69d5e83SAlexander Shishkin 		header |= MIPI_SYST_OPT_LEN;
310d69d5e83SAlexander Shishkin 	if (sys_t_need_ts(op))
311d69d5e83SAlexander Shishkin 		header |= MIPI_SYST_OPT_TS;
312d69d5e83SAlexander Shishkin 
313d69d5e83SAlexander Shishkin 	/*
314d69d5e83SAlexander Shishkin 	 * STP framing rules for SyS-T frames:
315d69d5e83SAlexander Shishkin 	 *   * the first packet of the SyS-T frame is timestamped;
316d69d5e83SAlexander Shishkin 	 *   * the last packet is a FLAG.
317d69d5e83SAlexander Shishkin 	 */
318d69d5e83SAlexander Shishkin 	/* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */
319d69d5e83SAlexander Shishkin 	/* HEADER */
320d69d5e83SAlexander Shishkin 	sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
321d69d5e83SAlexander Shishkin 			  4, (u8 *)&header);
322d69d5e83SAlexander Shishkin 	if (sz <= 0)
323d69d5e83SAlexander Shishkin 		return sz;
324d69d5e83SAlexander Shishkin 
325d69d5e83SAlexander Shishkin 	/* GUID */
326*41c9f7fbSAndy Shevchenko 	export_uuid(uuid, &op->node.uuid);
327*41c9f7fbSAndy Shevchenko 	sz = stm_data_write(data, m, c, false, uuid, sizeof(op->node.uuid));
328d69d5e83SAlexander Shishkin 	if (sz <= 0)
329d69d5e83SAlexander Shishkin 		return sz;
330d69d5e83SAlexander Shishkin 
331d69d5e83SAlexander Shishkin 	/* [LENGTH] */
332d69d5e83SAlexander Shishkin 	if (op->node.do_len) {
333d69d5e83SAlexander Shishkin 		u16 length = count;
334d69d5e83SAlexander Shishkin 
335d69d5e83SAlexander Shishkin 		sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2,
336d69d5e83SAlexander Shishkin 				  (u8 *)&length);
337d69d5e83SAlexander Shishkin 		if (sz <= 0)
338d69d5e83SAlexander Shishkin 			return sz;
339d69d5e83SAlexander Shishkin 	}
340d69d5e83SAlexander Shishkin 
341d69d5e83SAlexander Shishkin 	/* [TIMESTAMP] */
342d69d5e83SAlexander Shishkin 	if (header & MIPI_SYST_OPT_TS) {
343d69d5e83SAlexander Shishkin 		u64 ts = ktime_get_real_ns();
344d69d5e83SAlexander Shishkin 
345d69d5e83SAlexander Shishkin 		sz = stm_data_write(data, m, c, false, &ts, sizeof(ts));
346d69d5e83SAlexander Shishkin 		if (sz <= 0)
347d69d5e83SAlexander Shishkin 			return sz;
348d69d5e83SAlexander Shishkin 	}
349d69d5e83SAlexander Shishkin 
350d69d5e83SAlexander Shishkin 	/* DATA */
351d69d5e83SAlexander Shishkin 	sz = stm_data_write(data, m, c, false, buf, count);
352d69d5e83SAlexander Shishkin 	if (sz > 0)
353d69d5e83SAlexander Shishkin 		data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
354d69d5e83SAlexander Shishkin 
355d69d5e83SAlexander Shishkin 	return sz;
356d69d5e83SAlexander Shishkin }
357d69d5e83SAlexander Shishkin 
358d69d5e83SAlexander Shishkin static const struct stm_protocol_driver sys_t_pdrv = {
359d69d5e83SAlexander Shishkin 	.owner			= THIS_MODULE,
360d69d5e83SAlexander Shishkin 	.name			= "p_sys-t",
361d69d5e83SAlexander Shishkin 	.priv_sz		= sizeof(struct sys_t_policy_node),
362d69d5e83SAlexander Shishkin 	.write			= sys_t_write,
363d69d5e83SAlexander Shishkin 	.policy_attr		= sys_t_policy_attrs,
364d69d5e83SAlexander Shishkin 	.policy_node_init	= sys_t_policy_node_init,
365d69d5e83SAlexander Shishkin 	.output_open		= sys_t_output_open,
366d69d5e83SAlexander Shishkin 	.output_close		= sys_t_output_close,
367d69d5e83SAlexander Shishkin };
368d69d5e83SAlexander Shishkin 
sys_t_stm_init(void)369d69d5e83SAlexander Shishkin static int sys_t_stm_init(void)
370d69d5e83SAlexander Shishkin {
371d69d5e83SAlexander Shishkin 	return stm_register_protocol(&sys_t_pdrv);
372d69d5e83SAlexander Shishkin }
373d69d5e83SAlexander Shishkin 
sys_t_stm_exit(void)374d69d5e83SAlexander Shishkin static void sys_t_stm_exit(void)
375d69d5e83SAlexander Shishkin {
376d69d5e83SAlexander Shishkin 	stm_unregister_protocol(&sys_t_pdrv);
377d69d5e83SAlexander Shishkin }
378d69d5e83SAlexander Shishkin 
379d69d5e83SAlexander Shishkin module_init(sys_t_stm_init);
380d69d5e83SAlexander Shishkin module_exit(sys_t_stm_exit);
381d69d5e83SAlexander Shishkin 
382d69d5e83SAlexander Shishkin MODULE_LICENSE("GPL v2");
383d69d5e83SAlexander Shishkin MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver");
384d69d5e83SAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
385