18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * A dummy STM device for stm/stm_source class testing. 48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * STM class implements generic infrastructure for System Trace Module devices 78c2ecf20Sopenharmony_ci * as defined in MIPI STPv2 specification. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#undef DEBUG 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/stm.h> 158c2ecf20Sopenharmony_ci#include <uapi/linux/stm.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic ssize_t notrace 188c2ecf20Sopenharmony_cidummy_stm_packet(struct stm_data *stm_data, unsigned int master, 198c2ecf20Sopenharmony_ci unsigned int channel, unsigned int packet, unsigned int flags, 208c2ecf20Sopenharmony_ci unsigned int size, const unsigned char *payload) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci#ifdef DEBUG 238c2ecf20Sopenharmony_ci u64 pl = 0; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci if (payload) 268c2ecf20Sopenharmony_ci pl = *(u64 *)payload; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (size < 8) 298c2ecf20Sopenharmony_ci pl &= (1ull << (size * 8)) - 1; 308c2ecf20Sopenharmony_ci trace_printk("[%u:%u] [pkt: %x/%x] (%llx)\n", master, channel, 318c2ecf20Sopenharmony_ci packet, size, pl); 328c2ecf20Sopenharmony_ci#endif 338c2ecf20Sopenharmony_ci return size; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DUMMY_STM_MAX 32 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic struct stm_data dummy_stm[DUMMY_STM_MAX]; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int nr_dummies = 4; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cimodule_param(nr_dummies, int, 0400); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic unsigned int fail_mode; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cimodule_param(fail_mode, int, 0600); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic unsigned int master_min; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cimodule_param(master_min, int, 0400); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic unsigned int master_max = STP_MASTER_MAX; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cimodule_param(master_max, int, 0400); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic unsigned int nr_channels = STP_CHANNEL_MAX; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cimodule_param(nr_channels, int, 0400); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int dummy_stm_link(struct stm_data *data, unsigned int master, 618c2ecf20Sopenharmony_ci unsigned int channel) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci if (fail_mode && (channel & fail_mode)) 648c2ecf20Sopenharmony_ci return -EINVAL; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int dummy_stm_init(void) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int i, ret = -ENOMEM; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (nr_dummies < 0 || nr_dummies > DUMMY_STM_MAX) 748c2ecf20Sopenharmony_ci return -EINVAL; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (master_min > master_max || 778c2ecf20Sopenharmony_ci master_max > STP_MASTER_MAX || 788c2ecf20Sopenharmony_ci nr_channels > STP_CHANNEL_MAX) 798c2ecf20Sopenharmony_ci return -EINVAL; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci for (i = 0; i < nr_dummies; i++) { 828c2ecf20Sopenharmony_ci dummy_stm[i].name = kasprintf(GFP_KERNEL, "dummy_stm.%d", i); 838c2ecf20Sopenharmony_ci if (!dummy_stm[i].name) 848c2ecf20Sopenharmony_ci goto fail_unregister; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci dummy_stm[i].sw_start = master_min; 878c2ecf20Sopenharmony_ci dummy_stm[i].sw_end = master_max; 888c2ecf20Sopenharmony_ci dummy_stm[i].sw_nchannels = nr_channels; 898c2ecf20Sopenharmony_ci dummy_stm[i].packet = dummy_stm_packet; 908c2ecf20Sopenharmony_ci dummy_stm[i].link = dummy_stm_link; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = stm_register_device(NULL, &dummy_stm[i], THIS_MODULE); 938c2ecf20Sopenharmony_ci if (ret) 948c2ecf20Sopenharmony_ci goto fail_free; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cifail_unregister: 1008c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 1018c2ecf20Sopenharmony_ci stm_unregister_device(&dummy_stm[i]); 1028c2ecf20Sopenharmony_cifail_free: 1038c2ecf20Sopenharmony_ci kfree(dummy_stm[i].name); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void dummy_stm_exit(void) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int i; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < nr_dummies; i++) { 1158c2ecf20Sopenharmony_ci stm_unregister_device(&dummy_stm[i]); 1168c2ecf20Sopenharmony_ci kfree(dummy_stm[i].name); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cimodule_init(dummy_stm_init); 1218c2ecf20Sopenharmony_cimodule_exit(dummy_stm_exit); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("dummy_stm device"); 1258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 126