1 // SPDX-License-Identifier: GPL-2.0
3 * MIPI SyS-T framing protocol for STM devices.
4 * Copyright (c) 2018, Intel Corporation.
7 #include <linux/configfs.h>
8 #include <linux/module.h>
9 #include <linux/device.h>
10 #include <linux/slab.h>
11 #include <linux/uuid.h>
12 #include <linux/stm.h>
15 enum sys_t_message_type {
16 MIPI_SYST_TYPE_BUILD = 0,
17 MIPI_SYST_TYPE_SHORT32,
18 MIPI_SYST_TYPE_STRING,
19 MIPI_SYST_TYPE_CATALOG,
20 MIPI_SYST_TYPE_RAW = 6,
21 MIPI_SYST_TYPE_SHORT64,
25 enum sys_t_message_severity {
26 MIPI_SYST_SEVERITY_MAX = 0,
27 MIPI_SYST_SEVERITY_FATAL,
28 MIPI_SYST_SEVERITY_ERROR,
29 MIPI_SYST_SEVERITY_WARNING,
30 MIPI_SYST_SEVERITY_INFO,
31 MIPI_SYST_SEVERITY_USER1,
32 MIPI_SYST_SEVERITY_USER2,
33 MIPI_SYST_SEVERITY_DEBUG,
36 enum sys_t_message_build_subtype {
37 MIPI_SYST_BUILD_ID_COMPACT32 = 0,
38 MIPI_SYST_BUILD_ID_COMPACT64,
39 MIPI_SYST_BUILD_ID_LONG,
42 enum sys_t_message_clock_subtype {
43 MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1,
46 enum sys_t_message_string_subtype {
47 MIPI_SYST_STRING_GENERIC = 1,
48 MIPI_SYST_STRING_FUNCTIONENTER,
49 MIPI_SYST_STRING_FUNCTIONEXIT,
50 MIPI_SYST_STRING_INVALIDPARAM = 5,
51 MIPI_SYST_STRING_ASSERT = 7,
52 MIPI_SYST_STRING_PRINTF_32 = 11,
53 MIPI_SYST_STRING_PRINTF_64 = 12,
56 #define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t))
57 #define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4)
58 #define MIPI_SYST_OPT_LOC BIT(8)
59 #define MIPI_SYST_OPT_LEN BIT(9)
60 #define MIPI_SYST_OPT_CHK BIT(10)
61 #define MIPI_SYST_OPT_TS BIT(11)
62 #define MIPI_SYST_UNIT(u) ((u32)(u) << 12)
63 #define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16)
64 #define MIPI_SYST_OPT_GUID BIT(23)
65 #define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24)
66 #define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \
67 MIPI_SYST_ORIGIN(u >> 4))
68 #define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \
69 MIPI_SYST_SUBTYPE(t ## _ ## s))
71 #define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \
72 MIPI_SYST_SEVERITY(INFO) | \
75 struct sys_t_policy_node {
78 unsigned long ts_interval;
82 struct sys_t_policy_node node;
83 unsigned long ts_jiffies;
86 static void sys_t_policy_node_init(void *priv)
88 struct sys_t_policy_node *pn = priv;
90 generate_random_uuid(pn->uuid.b);
93 static int sys_t_output_open(void *priv, struct stm_output *output)
95 struct sys_t_policy_node *pn = priv;
96 struct sys_t_output *opriv;
98 opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC);
102 memcpy(&opriv->node, pn, sizeof(opriv->node));
103 output->pdrv_private = opriv;
108 static void sys_t_output_close(struct stm_output *output)
110 kfree(output->pdrv_private);
113 static ssize_t sys_t_policy_uuid_show(struct config_item *item,
116 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
118 return sprintf(page, "%pU\n", &pn->uuid);
122 sys_t_policy_uuid_store(struct config_item *item, const char *page,
125 struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
126 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
130 ret = uuid_parse(page, &pn->uuid);
131 mutex_unlock(mutexp);
133 return ret < 0 ? ret : count;
136 CONFIGFS_ATTR(sys_t_policy_, uuid);
138 static ssize_t sys_t_policy_do_len_show(struct config_item *item,
141 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
143 return sprintf(page, "%d\n", pn->do_len);
147 sys_t_policy_do_len_store(struct config_item *item, const char *page,
150 struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
151 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
155 ret = kstrtobool(page, &pn->do_len);
156 mutex_unlock(mutexp);
158 return ret ? ret : count;
161 CONFIGFS_ATTR(sys_t_policy_, do_len);
163 static ssize_t sys_t_policy_ts_interval_show(struct config_item *item,
166 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
168 return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval));
172 sys_t_policy_ts_interval_store(struct config_item *item, const char *page,
175 struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex;
176 struct sys_t_policy_node *pn = to_pdrv_policy_node(item);
181 ret = kstrtouint(page, 10, &ms);
182 mutex_unlock(mutexp);
185 pn->ts_interval = msecs_to_jiffies(ms);
192 CONFIGFS_ATTR(sys_t_policy_, ts_interval);
194 static struct configfs_attribute *sys_t_policy_attrs[] = {
195 &sys_t_policy_attr_uuid,
196 &sys_t_policy_attr_do_len,
197 &sys_t_policy_attr_ts_interval,
201 static inline bool sys_t_need_ts(struct sys_t_output *op)
203 if (op->node.ts_interval &&
204 time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) {
205 op->ts_jiffies = jiffies;
213 static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output,
214 unsigned int chan, const char *buf, size_t count)
216 struct sys_t_output *op = output->pdrv_private;
217 unsigned int c = output->channel + chan;
218 unsigned int m = output->master;
219 const unsigned char nil = 0;
220 u32 header = DATA_HEADER;
223 /* We require an existing policy node to proceed */
228 header |= MIPI_SYST_OPT_LEN;
229 if (sys_t_need_ts(op))
230 header |= MIPI_SYST_OPT_TS;
233 * STP framing rules for SyS-T frames:
234 * * the first packet of the SyS-T frame is timestamped;
235 * * the last packet is a FLAG.
237 /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */
239 sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED,
245 sz = stm_data_write(data, m, c, false, op->node.uuid.b, UUID_SIZE);
250 if (op->node.do_len) {
253 sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2,
260 if (header & MIPI_SYST_OPT_TS) {
261 u64 ts = ktime_get_real_ns();
263 sz = stm_data_write(data, m, c, false, &ts, sizeof(ts));
269 sz = stm_data_write(data, m, c, false, buf, count);
271 data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil);
276 static const struct stm_protocol_driver sys_t_pdrv = {
277 .owner = THIS_MODULE,
279 .priv_sz = sizeof(struct sys_t_policy_node),
280 .write = sys_t_write,
281 .policy_attr = sys_t_policy_attrs,
282 .policy_node_init = sys_t_policy_node_init,
283 .output_open = sys_t_output_open,
284 .output_close = sys_t_output_close,
287 static int sys_t_stm_init(void)
289 return stm_register_protocol(&sys_t_pdrv);
292 static void sys_t_stm_exit(void)
294 stm_unregister_protocol(&sys_t_pdrv);
297 module_init(sys_t_stm_init);
298 module_exit(sys_t_stm_exit);
300 MODULE_LICENSE("GPL v2");
301 MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver");
302 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");