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, 23*3c720592SMikhail Lappo MIPI_SYST_TYPE_SBD, 24d69d5e83SAlexander Shishkin }; 25d69d5e83SAlexander Shishkin 26d69d5e83SAlexander Shishkin enum sys_t_message_severity { 27d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_MAX = 0, 28d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_FATAL, 29d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_ERROR, 30d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_WARNING, 31d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_INFO, 32d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_USER1, 33d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_USER2, 34d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY_DEBUG, 35d69d5e83SAlexander Shishkin }; 36d69d5e83SAlexander Shishkin 37d69d5e83SAlexander Shishkin enum sys_t_message_build_subtype { 38d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_COMPACT32 = 0, 39d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_COMPACT64, 40d69d5e83SAlexander Shishkin MIPI_SYST_BUILD_ID_LONG, 41d69d5e83SAlexander Shishkin }; 42d69d5e83SAlexander Shishkin 43d69d5e83SAlexander Shishkin enum sys_t_message_clock_subtype { 44d69d5e83SAlexander Shishkin MIPI_SYST_CLOCK_TRANSPORT_SYNC = 1, 45d69d5e83SAlexander Shishkin }; 46d69d5e83SAlexander Shishkin 47d69d5e83SAlexander Shishkin enum sys_t_message_string_subtype { 48d69d5e83SAlexander Shishkin MIPI_SYST_STRING_GENERIC = 1, 49d69d5e83SAlexander Shishkin MIPI_SYST_STRING_FUNCTIONENTER, 50d69d5e83SAlexander Shishkin MIPI_SYST_STRING_FUNCTIONEXIT, 51d69d5e83SAlexander Shishkin MIPI_SYST_STRING_INVALIDPARAM = 5, 52d69d5e83SAlexander Shishkin MIPI_SYST_STRING_ASSERT = 7, 53d69d5e83SAlexander Shishkin MIPI_SYST_STRING_PRINTF_32 = 11, 54d69d5e83SAlexander Shishkin MIPI_SYST_STRING_PRINTF_64 = 12, 55d69d5e83SAlexander Shishkin }; 56d69d5e83SAlexander Shishkin 57*3c720592SMikhail Lappo /** 58*3c720592SMikhail Lappo * enum sys_t_message_sbd_subtype - SyS-T SBD message subtypes 59*3c720592SMikhail Lappo * @MIPI_SYST_SBD_ID32: SBD message with 32-bit message ID 60*3c720592SMikhail Lappo * @MIPI_SYST_SBD_ID64: SBD message with 64-bit message ID 61*3c720592SMikhail Lappo * 62*3c720592SMikhail Lappo * Structured Binary Data messages can send information of arbitrary length, 63*3c720592SMikhail Lappo * together with ID's that describe BLOB's content and layout. 64*3c720592SMikhail Lappo */ 65*3c720592SMikhail Lappo enum sys_t_message_sbd_subtype { 66*3c720592SMikhail Lappo MIPI_SYST_SBD_ID32 = 0, 67*3c720592SMikhail Lappo MIPI_SYST_SBD_ID64 = 1, 68*3c720592SMikhail Lappo }; 69*3c720592SMikhail Lappo 70d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t)) 71d69d5e83SAlexander Shishkin #define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4) 72d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LOC BIT(8) 73d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_LEN BIT(9) 74d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_CHK BIT(10) 75d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_TS BIT(11) 76d69d5e83SAlexander Shishkin #define MIPI_SYST_UNIT(u) ((u32)(u) << 12) 77d69d5e83SAlexander Shishkin #define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16) 78d69d5e83SAlexander Shishkin #define MIPI_SYST_OPT_GUID BIT(23) 79d69d5e83SAlexander Shishkin #define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24) 80d69d5e83SAlexander Shishkin #define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \ 81d69d5e83SAlexander Shishkin MIPI_SYST_ORIGIN(u >> 4)) 82d69d5e83SAlexander Shishkin #define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \ 83d69d5e83SAlexander Shishkin MIPI_SYST_SUBTYPE(t ## _ ## s)) 84d69d5e83SAlexander Shishkin 85d69d5e83SAlexander Shishkin #define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \ 86d69d5e83SAlexander Shishkin MIPI_SYST_SEVERITY(INFO) | \ 87d69d5e83SAlexander Shishkin MIPI_SYST_OPT_GUID) 88d69d5e83SAlexander Shishkin 8939f10239SAlexander Shishkin #define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \ 9039f10239SAlexander Shishkin MIPI_SYST_SEVERITY(MAX)) 9139f10239SAlexander Shishkin 92*3c720592SMikhail Lappo /* 93*3c720592SMikhail Lappo * SyS-T and ftrace headers are compatible to an extent that ftrace event ID 94*3c720592SMikhail Lappo * and args can be treated as SyS-T SBD message with 64-bit ID and arguments 95*3c720592SMikhail Lappo * BLOB right behind the header without modification. Bits [16:63] coming 96*3c720592SMikhail Lappo * together with message ID from ftrace aren't used by SBD and must be zeroed. 97*3c720592SMikhail Lappo * 98*3c720592SMikhail Lappo * 0 15 16 23 24 31 32 39 40 63 99*3c720592SMikhail Lappo * ftrace: <event_id> <flags> <preempt> <-pid-> <----> <args> 100*3c720592SMikhail Lappo * SBD: <------- msg_id ------------------------------> <BLOB> 101*3c720592SMikhail Lappo */ 102*3c720592SMikhail Lappo #define SBD_HEADER (MIPI_SYST_TYPES(SBD, ID64) | \ 103*3c720592SMikhail Lappo MIPI_SYST_SEVERITY(INFO) | \ 104*3c720592SMikhail Lappo MIPI_SYST_OPT_GUID) 105*3c720592SMikhail Lappo 106d69d5e83SAlexander Shishkin struct sys_t_policy_node { 107d69d5e83SAlexander Shishkin uuid_t uuid; 108d69d5e83SAlexander Shishkin bool do_len; 109d69d5e83SAlexander Shishkin unsigned long ts_interval; 11039f10239SAlexander Shishkin unsigned long clocksync_interval; 111d69d5e83SAlexander Shishkin }; 112d69d5e83SAlexander Shishkin 113d69d5e83SAlexander Shishkin struct sys_t_output { 114d69d5e83SAlexander Shishkin struct sys_t_policy_node node; 115d69d5e83SAlexander Shishkin unsigned long ts_jiffies; 11639f10239SAlexander Shishkin unsigned long clocksync_jiffies; 117d69d5e83SAlexander Shishkin }; 118d69d5e83SAlexander Shishkin 119d69d5e83SAlexander Shishkin static void sys_t_policy_node_init(void *priv) 120d69d5e83SAlexander Shishkin { 121d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = priv; 122d69d5e83SAlexander Shishkin 12341c9f7fbSAndy Shevchenko uuid_gen(&pn->uuid); 124d69d5e83SAlexander Shishkin } 125d69d5e83SAlexander Shishkin 126d69d5e83SAlexander Shishkin static int sys_t_output_open(void *priv, struct stm_output *output) 127d69d5e83SAlexander Shishkin { 128d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = priv; 129d69d5e83SAlexander Shishkin struct sys_t_output *opriv; 130d69d5e83SAlexander Shishkin 131d69d5e83SAlexander Shishkin opriv = kzalloc(sizeof(*opriv), GFP_ATOMIC); 132d69d5e83SAlexander Shishkin if (!opriv) 133d69d5e83SAlexander Shishkin return -ENOMEM; 134d69d5e83SAlexander Shishkin 135d69d5e83SAlexander Shishkin memcpy(&opriv->node, pn, sizeof(opriv->node)); 136d69d5e83SAlexander Shishkin output->pdrv_private = opriv; 137d69d5e83SAlexander Shishkin 138d69d5e83SAlexander Shishkin return 0; 139d69d5e83SAlexander Shishkin } 140d69d5e83SAlexander Shishkin 141d69d5e83SAlexander Shishkin static void sys_t_output_close(struct stm_output *output) 142d69d5e83SAlexander Shishkin { 143d69d5e83SAlexander Shishkin kfree(output->pdrv_private); 144d69d5e83SAlexander Shishkin } 145d69d5e83SAlexander Shishkin 146d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_uuid_show(struct config_item *item, 147d69d5e83SAlexander Shishkin char *page) 148d69d5e83SAlexander Shishkin { 149d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 150d69d5e83SAlexander Shishkin 151d69d5e83SAlexander Shishkin return sprintf(page, "%pU\n", &pn->uuid); 152d69d5e83SAlexander Shishkin } 153d69d5e83SAlexander Shishkin 154d69d5e83SAlexander Shishkin static ssize_t 155d69d5e83SAlexander Shishkin sys_t_policy_uuid_store(struct config_item *item, const char *page, 156d69d5e83SAlexander Shishkin size_t count) 157d69d5e83SAlexander Shishkin { 158d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 159d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 160d69d5e83SAlexander Shishkin int ret; 161d69d5e83SAlexander Shishkin 162d69d5e83SAlexander Shishkin mutex_lock(mutexp); 163d69d5e83SAlexander Shishkin ret = uuid_parse(page, &pn->uuid); 164d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 165d69d5e83SAlexander Shishkin 166d69d5e83SAlexander Shishkin return ret < 0 ? ret : count; 167d69d5e83SAlexander Shishkin } 168d69d5e83SAlexander Shishkin 169d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, uuid); 170d69d5e83SAlexander Shishkin 171d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_do_len_show(struct config_item *item, 172d69d5e83SAlexander Shishkin char *page) 173d69d5e83SAlexander Shishkin { 174d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 175d69d5e83SAlexander Shishkin 176d69d5e83SAlexander Shishkin return sprintf(page, "%d\n", pn->do_len); 177d69d5e83SAlexander Shishkin } 178d69d5e83SAlexander Shishkin 179d69d5e83SAlexander Shishkin static ssize_t 180d69d5e83SAlexander Shishkin sys_t_policy_do_len_store(struct config_item *item, const char *page, 181d69d5e83SAlexander Shishkin size_t count) 182d69d5e83SAlexander Shishkin { 183d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 184d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 185d69d5e83SAlexander Shishkin int ret; 186d69d5e83SAlexander Shishkin 187d69d5e83SAlexander Shishkin mutex_lock(mutexp); 188d69d5e83SAlexander Shishkin ret = kstrtobool(page, &pn->do_len); 189d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 190d69d5e83SAlexander Shishkin 191d69d5e83SAlexander Shishkin return ret ? ret : count; 192d69d5e83SAlexander Shishkin } 193d69d5e83SAlexander Shishkin 194d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, do_len); 195d69d5e83SAlexander Shishkin 196d69d5e83SAlexander Shishkin static ssize_t sys_t_policy_ts_interval_show(struct config_item *item, 197d69d5e83SAlexander Shishkin char *page) 198d69d5e83SAlexander Shishkin { 199d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 200d69d5e83SAlexander Shishkin 201d69d5e83SAlexander Shishkin return sprintf(page, "%u\n", jiffies_to_msecs(pn->ts_interval)); 202d69d5e83SAlexander Shishkin } 203d69d5e83SAlexander Shishkin 204d69d5e83SAlexander Shishkin static ssize_t 205d69d5e83SAlexander Shishkin sys_t_policy_ts_interval_store(struct config_item *item, const char *page, 206d69d5e83SAlexander Shishkin size_t count) 207d69d5e83SAlexander Shishkin { 208d69d5e83SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 209d69d5e83SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 210d69d5e83SAlexander Shishkin unsigned int ms; 211d69d5e83SAlexander Shishkin int ret; 212d69d5e83SAlexander Shishkin 213d69d5e83SAlexander Shishkin mutex_lock(mutexp); 214d69d5e83SAlexander Shishkin ret = kstrtouint(page, 10, &ms); 215d69d5e83SAlexander Shishkin mutex_unlock(mutexp); 216d69d5e83SAlexander Shishkin 217d69d5e83SAlexander Shishkin if (!ret) { 218d69d5e83SAlexander Shishkin pn->ts_interval = msecs_to_jiffies(ms); 219d69d5e83SAlexander Shishkin return count; 220d69d5e83SAlexander Shishkin } 221d69d5e83SAlexander Shishkin 222d69d5e83SAlexander Shishkin return ret; 223d69d5e83SAlexander Shishkin } 224d69d5e83SAlexander Shishkin 225d69d5e83SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, ts_interval); 226d69d5e83SAlexander Shishkin 22739f10239SAlexander Shishkin static ssize_t sys_t_policy_clocksync_interval_show(struct config_item *item, 22839f10239SAlexander Shishkin char *page) 22939f10239SAlexander Shishkin { 23039f10239SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 23139f10239SAlexander Shishkin 23239f10239SAlexander Shishkin return sprintf(page, "%u\n", jiffies_to_msecs(pn->clocksync_interval)); 23339f10239SAlexander Shishkin } 23439f10239SAlexander Shishkin 23539f10239SAlexander Shishkin static ssize_t 23639f10239SAlexander Shishkin sys_t_policy_clocksync_interval_store(struct config_item *item, 23739f10239SAlexander Shishkin const char *page, size_t count) 23839f10239SAlexander Shishkin { 23939f10239SAlexander Shishkin struct mutex *mutexp = &item->ci_group->cg_subsys->su_mutex; 24039f10239SAlexander Shishkin struct sys_t_policy_node *pn = to_pdrv_policy_node(item); 24139f10239SAlexander Shishkin unsigned int ms; 24239f10239SAlexander Shishkin int ret; 24339f10239SAlexander Shishkin 24439f10239SAlexander Shishkin mutex_lock(mutexp); 24539f10239SAlexander Shishkin ret = kstrtouint(page, 10, &ms); 24639f10239SAlexander Shishkin mutex_unlock(mutexp); 24739f10239SAlexander Shishkin 24839f10239SAlexander Shishkin if (!ret) { 24939f10239SAlexander Shishkin pn->clocksync_interval = msecs_to_jiffies(ms); 25039f10239SAlexander Shishkin return count; 25139f10239SAlexander Shishkin } 25239f10239SAlexander Shishkin 25339f10239SAlexander Shishkin return ret; 25439f10239SAlexander Shishkin } 25539f10239SAlexander Shishkin 25639f10239SAlexander Shishkin CONFIGFS_ATTR(sys_t_policy_, clocksync_interval); 25739f10239SAlexander Shishkin 258d69d5e83SAlexander Shishkin static struct configfs_attribute *sys_t_policy_attrs[] = { 259d69d5e83SAlexander Shishkin &sys_t_policy_attr_uuid, 260d69d5e83SAlexander Shishkin &sys_t_policy_attr_do_len, 261d69d5e83SAlexander Shishkin &sys_t_policy_attr_ts_interval, 26239f10239SAlexander Shishkin &sys_t_policy_attr_clocksync_interval, 263d69d5e83SAlexander Shishkin NULL, 264d69d5e83SAlexander Shishkin }; 265d69d5e83SAlexander Shishkin 266d69d5e83SAlexander Shishkin static inline bool sys_t_need_ts(struct sys_t_output *op) 267d69d5e83SAlexander Shishkin { 268d69d5e83SAlexander Shishkin if (op->node.ts_interval && 269283f87c0SAlexander Shishkin time_after(jiffies, op->ts_jiffies + op->node.ts_interval)) { 270d69d5e83SAlexander Shishkin op->ts_jiffies = jiffies; 271d69d5e83SAlexander Shishkin 272d69d5e83SAlexander Shishkin return true; 273d69d5e83SAlexander Shishkin } 274d69d5e83SAlexander Shishkin 275d69d5e83SAlexander Shishkin return false; 276d69d5e83SAlexander Shishkin } 277d69d5e83SAlexander Shishkin 27839f10239SAlexander Shishkin static bool sys_t_need_clock_sync(struct sys_t_output *op) 27939f10239SAlexander Shishkin { 28039f10239SAlexander Shishkin if (op->node.clocksync_interval && 281283f87c0SAlexander Shishkin time_after(jiffies, 282283f87c0SAlexander Shishkin op->clocksync_jiffies + op->node.clocksync_interval)) { 28339f10239SAlexander Shishkin op->clocksync_jiffies = jiffies; 28439f10239SAlexander Shishkin 28539f10239SAlexander Shishkin return true; 28639f10239SAlexander Shishkin } 28739f10239SAlexander Shishkin 28839f10239SAlexander Shishkin return false; 28939f10239SAlexander Shishkin } 29039f10239SAlexander Shishkin 29139f10239SAlexander Shishkin static ssize_t 29239f10239SAlexander Shishkin sys_t_clock_sync(struct stm_data *data, unsigned int m, unsigned int c) 29339f10239SAlexander Shishkin { 29439f10239SAlexander Shishkin u32 header = CLOCK_SYNC_HEADER; 29539f10239SAlexander Shishkin const unsigned char nil = 0; 29639f10239SAlexander Shishkin u64 payload[2]; /* Clock value and frequency */ 29739f10239SAlexander Shishkin ssize_t sz; 29839f10239SAlexander Shishkin 29939f10239SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, 30039f10239SAlexander Shishkin 4, (u8 *)&header); 30139f10239SAlexander Shishkin if (sz <= 0) 30239f10239SAlexander Shishkin return sz; 30339f10239SAlexander Shishkin 30439f10239SAlexander Shishkin payload[0] = ktime_get_real_ns(); 30539f10239SAlexander Shishkin payload[1] = NSEC_PER_SEC; 30639f10239SAlexander Shishkin sz = stm_data_write(data, m, c, false, &payload, sizeof(payload)); 30739f10239SAlexander Shishkin if (sz <= 0) 30839f10239SAlexander Shishkin return sz; 30939f10239SAlexander Shishkin 31039f10239SAlexander Shishkin data->packet(data, m, c, STP_PACKET_FLAG, 0, 0, &nil); 31139f10239SAlexander Shishkin 31239f10239SAlexander Shishkin return sizeof(header) + sizeof(payload); 31339f10239SAlexander Shishkin } 31439f10239SAlexander Shishkin 315*3c720592SMikhail Lappo static inline u32 sys_t_header(struct stm_source_data *source) 316*3c720592SMikhail Lappo { 317*3c720592SMikhail Lappo if (source && source->type == STM_FTRACE) 318*3c720592SMikhail Lappo return SBD_HEADER; 319*3c720592SMikhail Lappo return DATA_HEADER; 320*3c720592SMikhail Lappo } 321*3c720592SMikhail Lappo 322*3c720592SMikhail Lappo static ssize_t sys_t_write_data(struct stm_data *data, 323*3c720592SMikhail Lappo struct stm_source_data *source, 324*3c720592SMikhail Lappo unsigned int master, unsigned int channel, 325*3c720592SMikhail Lappo bool ts_first, const void *buf, size_t count) 326*3c720592SMikhail Lappo { 327*3c720592SMikhail Lappo ssize_t sz; 328*3c720592SMikhail Lappo const unsigned char nil = 0; 329*3c720592SMikhail Lappo 330*3c720592SMikhail Lappo /* 331*3c720592SMikhail Lappo * Ftrace is zero-copy compatible with SyS-T SBD, but requires 332*3c720592SMikhail Lappo * special handling of first 64 bits. Trim and send them separately 333*3c720592SMikhail Lappo * to avoid damage on original ftrace buffer. 334*3c720592SMikhail Lappo */ 335*3c720592SMikhail Lappo if (source && source->type == STM_FTRACE) { 336*3c720592SMikhail Lappo u64 compat_ftrace_header; 337*3c720592SMikhail Lappo ssize_t header_sz; 338*3c720592SMikhail Lappo ssize_t buf_sz; 339*3c720592SMikhail Lappo 340*3c720592SMikhail Lappo if (count < sizeof(compat_ftrace_header)) 341*3c720592SMikhail Lappo return -EINVAL; 342*3c720592SMikhail Lappo 343*3c720592SMikhail Lappo /* SBD only makes use of low 16 bits (event ID) from ftrace event */ 344*3c720592SMikhail Lappo compat_ftrace_header = *(u64 *)buf & 0xffff; 345*3c720592SMikhail Lappo header_sz = stm_data_write(data, master, channel, false, 346*3c720592SMikhail Lappo &compat_ftrace_header, 347*3c720592SMikhail Lappo sizeof(compat_ftrace_header)); 348*3c720592SMikhail Lappo if (header_sz != sizeof(compat_ftrace_header)) 349*3c720592SMikhail Lappo return header_sz; 350*3c720592SMikhail Lappo 351*3c720592SMikhail Lappo buf_sz = stm_data_write(data, master, channel, false, 352*3c720592SMikhail Lappo buf + header_sz, count - header_sz); 353*3c720592SMikhail Lappo if (buf_sz != count - header_sz) 354*3c720592SMikhail Lappo return buf_sz; 355*3c720592SMikhail Lappo sz = header_sz + buf_sz; 356*3c720592SMikhail Lappo } else { 357*3c720592SMikhail Lappo sz = stm_data_write(data, master, channel, false, buf, count); 358*3c720592SMikhail Lappo } 359*3c720592SMikhail Lappo 360*3c720592SMikhail Lappo if (sz <= 0) 361*3c720592SMikhail Lappo return sz; 362*3c720592SMikhail Lappo 363*3c720592SMikhail Lappo data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil); 364*3c720592SMikhail Lappo 365*3c720592SMikhail Lappo return sz; 366*3c720592SMikhail Lappo } 367*3c720592SMikhail Lappo 368d69d5e83SAlexander Shishkin static ssize_t sys_t_write(struct stm_data *data, struct stm_output *output, 369ee27f44eSMikhail Lappo unsigned int chan, const char *buf, size_t count, 370ee27f44eSMikhail Lappo struct stm_source_data *source) 371d69d5e83SAlexander Shishkin { 372d69d5e83SAlexander Shishkin struct sys_t_output *op = output->pdrv_private; 373d69d5e83SAlexander Shishkin unsigned int c = output->channel + chan; 374d69d5e83SAlexander Shishkin unsigned int m = output->master; 375*3c720592SMikhail Lappo u32 header = sys_t_header(source); 37641c9f7fbSAndy Shevchenko u8 uuid[UUID_SIZE]; 377d69d5e83SAlexander Shishkin ssize_t sz; 378d69d5e83SAlexander Shishkin 379d69d5e83SAlexander Shishkin /* We require an existing policy node to proceed */ 380d69d5e83SAlexander Shishkin if (!op) 381d69d5e83SAlexander Shishkin return -EINVAL; 382d69d5e83SAlexander Shishkin 38339f10239SAlexander Shishkin if (sys_t_need_clock_sync(op)) { 38439f10239SAlexander Shishkin sz = sys_t_clock_sync(data, m, c); 38539f10239SAlexander Shishkin if (sz <= 0) 38639f10239SAlexander Shishkin return sz; 38739f10239SAlexander Shishkin } 38839f10239SAlexander Shishkin 389d69d5e83SAlexander Shishkin if (op->node.do_len) 390d69d5e83SAlexander Shishkin header |= MIPI_SYST_OPT_LEN; 391d69d5e83SAlexander Shishkin if (sys_t_need_ts(op)) 392d69d5e83SAlexander Shishkin header |= MIPI_SYST_OPT_TS; 393d69d5e83SAlexander Shishkin 394d69d5e83SAlexander Shishkin /* 395d69d5e83SAlexander Shishkin * STP framing rules for SyS-T frames: 396d69d5e83SAlexander Shishkin * * the first packet of the SyS-T frame is timestamped; 397d69d5e83SAlexander Shishkin * * the last packet is a FLAG. 398d69d5e83SAlexander Shishkin */ 399d69d5e83SAlexander Shishkin /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */ 400d69d5e83SAlexander Shishkin /* HEADER */ 401d69d5e83SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, STP_PACKET_TIMESTAMPED, 402d69d5e83SAlexander Shishkin 4, (u8 *)&header); 403d69d5e83SAlexander Shishkin if (sz <= 0) 404d69d5e83SAlexander Shishkin return sz; 405d69d5e83SAlexander Shishkin 406d69d5e83SAlexander Shishkin /* GUID */ 40741c9f7fbSAndy Shevchenko export_uuid(uuid, &op->node.uuid); 40841c9f7fbSAndy Shevchenko sz = stm_data_write(data, m, c, false, uuid, sizeof(op->node.uuid)); 409d69d5e83SAlexander Shishkin if (sz <= 0) 410d69d5e83SAlexander Shishkin return sz; 411d69d5e83SAlexander Shishkin 412d69d5e83SAlexander Shishkin /* [LENGTH] */ 413d69d5e83SAlexander Shishkin if (op->node.do_len) { 414d69d5e83SAlexander Shishkin u16 length = count; 415d69d5e83SAlexander Shishkin 416d69d5e83SAlexander Shishkin sz = data->packet(data, m, c, STP_PACKET_DATA, 0, 2, 417d69d5e83SAlexander Shishkin (u8 *)&length); 418d69d5e83SAlexander Shishkin if (sz <= 0) 419d69d5e83SAlexander Shishkin return sz; 420d69d5e83SAlexander Shishkin } 421d69d5e83SAlexander Shishkin 422d69d5e83SAlexander Shishkin /* [TIMESTAMP] */ 423d69d5e83SAlexander Shishkin if (header & MIPI_SYST_OPT_TS) { 424d69d5e83SAlexander Shishkin u64 ts = ktime_get_real_ns(); 425d69d5e83SAlexander Shishkin 426d69d5e83SAlexander Shishkin sz = stm_data_write(data, m, c, false, &ts, sizeof(ts)); 427d69d5e83SAlexander Shishkin if (sz <= 0) 428d69d5e83SAlexander Shishkin return sz; 429d69d5e83SAlexander Shishkin } 430d69d5e83SAlexander Shishkin 431d69d5e83SAlexander Shishkin /* DATA */ 432*3c720592SMikhail Lappo return sys_t_write_data(data, source, m, c, false, buf, count); 433d69d5e83SAlexander Shishkin } 434d69d5e83SAlexander Shishkin 435d69d5e83SAlexander Shishkin static const struct stm_protocol_driver sys_t_pdrv = { 436d69d5e83SAlexander Shishkin .owner = THIS_MODULE, 437d69d5e83SAlexander Shishkin .name = "p_sys-t", 438d69d5e83SAlexander Shishkin .priv_sz = sizeof(struct sys_t_policy_node), 439d69d5e83SAlexander Shishkin .write = sys_t_write, 440d69d5e83SAlexander Shishkin .policy_attr = sys_t_policy_attrs, 441d69d5e83SAlexander Shishkin .policy_node_init = sys_t_policy_node_init, 442d69d5e83SAlexander Shishkin .output_open = sys_t_output_open, 443d69d5e83SAlexander Shishkin .output_close = sys_t_output_close, 444d69d5e83SAlexander Shishkin }; 445d69d5e83SAlexander Shishkin 446d69d5e83SAlexander Shishkin static int sys_t_stm_init(void) 447d69d5e83SAlexander Shishkin { 448d69d5e83SAlexander Shishkin return stm_register_protocol(&sys_t_pdrv); 449d69d5e83SAlexander Shishkin } 450d69d5e83SAlexander Shishkin 451d69d5e83SAlexander Shishkin static void sys_t_stm_exit(void) 452d69d5e83SAlexander Shishkin { 453d69d5e83SAlexander Shishkin stm_unregister_protocol(&sys_t_pdrv); 454d69d5e83SAlexander Shishkin } 455d69d5e83SAlexander Shishkin 456d69d5e83SAlexander Shishkin module_init(sys_t_stm_init); 457d69d5e83SAlexander Shishkin module_exit(sys_t_stm_exit); 458d69d5e83SAlexander Shishkin 459d69d5e83SAlexander Shishkin MODULE_LICENSE("GPL v2"); 460d69d5e83SAlexander Shishkin MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver"); 461d69d5e83SAlexander Shishkin MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 462