1 /* 2 * Simple heartbeat STM source driver 3 * Copyright (c) 2016, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * Heartbeat STM source will send repetitive messages over STM devices to a 15 * trace host. 16 */ 17 18 #include <linux/kernel.h> 19 #include <linux/module.h> 20 #include <linux/hrtimer.h> 21 #include <linux/slab.h> 22 #include <linux/stm.h> 23 24 #define STM_HEARTBEAT_MAX 32 25 26 static int nr_devs = 4; 27 static int interval_ms = 10; 28 29 module_param(nr_devs, int, 0600); 30 module_param(interval_ms, int, 0600); 31 32 static struct stm_heartbeat { 33 struct stm_source_data data; 34 struct hrtimer hrtimer; 35 unsigned int active; 36 } stm_heartbeat[STM_HEARTBEAT_MAX]; 37 38 static unsigned int nr_instances; 39 40 static const char str[] = "heartbeat stm source driver is here to serve you"; 41 42 static enum hrtimer_restart stm_heartbeat_hrtimer_handler(struct hrtimer *hr) 43 { 44 struct stm_heartbeat *heartbeat = container_of(hr, struct stm_heartbeat, 45 hrtimer); 46 47 stm_source_write(&heartbeat->data, 0, str, sizeof str); 48 if (heartbeat->active) 49 hrtimer_forward_now(hr, ms_to_ktime(interval_ms)); 50 51 return heartbeat->active ? HRTIMER_RESTART : HRTIMER_NORESTART; 52 } 53 54 static int stm_heartbeat_link(struct stm_source_data *data) 55 { 56 struct stm_heartbeat *heartbeat = 57 container_of(data, struct stm_heartbeat, data); 58 59 heartbeat->active = 1; 60 hrtimer_start(&heartbeat->hrtimer, ms_to_ktime(interval_ms), 61 HRTIMER_MODE_ABS); 62 63 return 0; 64 } 65 66 static void stm_heartbeat_unlink(struct stm_source_data *data) 67 { 68 struct stm_heartbeat *heartbeat = 69 container_of(data, struct stm_heartbeat, data); 70 71 heartbeat->active = 0; 72 hrtimer_cancel(&heartbeat->hrtimer); 73 } 74 75 static int stm_heartbeat_init(void) 76 { 77 int i, ret = -ENOMEM, __nr_instances = ACCESS_ONCE(nr_devs); 78 79 if (__nr_instances < 0 || __nr_instances > STM_HEARTBEAT_MAX) 80 return -EINVAL; 81 82 for (i = 0; i < __nr_instances; i++) { 83 stm_heartbeat[i].data.name = 84 kasprintf(GFP_KERNEL, "heartbeat.%d", i); 85 if (!stm_heartbeat[i].data.name) 86 goto fail_unregister; 87 88 stm_heartbeat[i].data.nr_chans = 1; 89 stm_heartbeat[i].data.link = stm_heartbeat_link; 90 stm_heartbeat[i].data.unlink = stm_heartbeat_unlink; 91 hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC, 92 HRTIMER_MODE_ABS); 93 stm_heartbeat[i].hrtimer.function = 94 stm_heartbeat_hrtimer_handler; 95 96 ret = stm_source_register_device(NULL, &stm_heartbeat[i].data); 97 if (ret) 98 goto fail_free; 99 } 100 101 nr_instances = __nr_instances; 102 103 return 0; 104 105 fail_unregister: 106 for (i--; i >= 0; i--) { 107 stm_source_unregister_device(&stm_heartbeat[i].data); 108 fail_free: 109 kfree(stm_heartbeat[i].data.name); 110 } 111 112 return ret; 113 } 114 115 static void stm_heartbeat_exit(void) 116 { 117 int i; 118 119 for (i = 0; i < nr_instances; i++) { 120 stm_source_unregister_device(&stm_heartbeat[i].data); 121 kfree(stm_heartbeat[i].data.name); 122 } 123 } 124 125 module_init(stm_heartbeat_init); 126 module_exit(stm_heartbeat_exit); 127 128 MODULE_LICENSE("GPL v2"); 129 MODULE_DESCRIPTION("stm_heartbeat driver"); 130 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 131