Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Simple heartbeat STM source driver
0004  * Copyright (c) 2016, Intel Corporation.
0005  *
0006  * Heartbeat STM source will send repetitive messages over STM devices to a
0007  * trace host.
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/hrtimer.h>
0013 #include <linux/slab.h>
0014 #include <linux/stm.h>
0015 
0016 #define STM_HEARTBEAT_MAX   32
0017 
0018 static int nr_devs = 4;
0019 static int interval_ms = 10;
0020 
0021 module_param(nr_devs, int, 0400);
0022 module_param(interval_ms, int, 0600);
0023 
0024 static struct stm_heartbeat {
0025     struct stm_source_data  data;
0026     struct hrtimer      hrtimer;
0027     unsigned int        active;
0028 } stm_heartbeat[STM_HEARTBEAT_MAX];
0029 
0030 static const char str[] = "heartbeat stm source driver is here to serve you";
0031 
0032 static enum hrtimer_restart stm_heartbeat_hrtimer_handler(struct hrtimer *hr)
0033 {
0034     struct stm_heartbeat *heartbeat = container_of(hr, struct stm_heartbeat,
0035                                hrtimer);
0036 
0037     stm_source_write(&heartbeat->data, 0, str, sizeof str);
0038     if (heartbeat->active)
0039         hrtimer_forward_now(hr, ms_to_ktime(interval_ms));
0040 
0041     return heartbeat->active ? HRTIMER_RESTART : HRTIMER_NORESTART;
0042 }
0043 
0044 static int stm_heartbeat_link(struct stm_source_data *data)
0045 {
0046     struct stm_heartbeat *heartbeat =
0047         container_of(data, struct stm_heartbeat, data);
0048 
0049     heartbeat->active = 1;
0050     hrtimer_start(&heartbeat->hrtimer, ms_to_ktime(interval_ms),
0051               HRTIMER_MODE_ABS);
0052 
0053     return 0;
0054 }
0055 
0056 static void stm_heartbeat_unlink(struct stm_source_data *data)
0057 {
0058     struct stm_heartbeat *heartbeat =
0059         container_of(data, struct stm_heartbeat, data);
0060 
0061     heartbeat->active = 0;
0062     hrtimer_cancel(&heartbeat->hrtimer);
0063 }
0064 
0065 static int stm_heartbeat_init(void)
0066 {
0067     int i, ret;
0068 
0069     if (nr_devs < 0 || nr_devs > STM_HEARTBEAT_MAX)
0070         return -EINVAL;
0071 
0072     for (i = 0; i < nr_devs; i++) {
0073         stm_heartbeat[i].data.name =
0074             kasprintf(GFP_KERNEL, "heartbeat.%d", i);
0075         if (!stm_heartbeat[i].data.name) {
0076             ret = -ENOMEM;
0077             goto fail_unregister;
0078         }
0079 
0080         stm_heartbeat[i].data.nr_chans  = 1;
0081         stm_heartbeat[i].data.link  = stm_heartbeat_link;
0082         stm_heartbeat[i].data.unlink    = stm_heartbeat_unlink;
0083         hrtimer_init(&stm_heartbeat[i].hrtimer, CLOCK_MONOTONIC,
0084                  HRTIMER_MODE_ABS);
0085         stm_heartbeat[i].hrtimer.function =
0086             stm_heartbeat_hrtimer_handler;
0087 
0088         ret = stm_source_register_device(NULL, &stm_heartbeat[i].data);
0089         if (ret)
0090             goto fail_free;
0091     }
0092 
0093     return 0;
0094 
0095 fail_unregister:
0096     for (i--; i >= 0; i--) {
0097         stm_source_unregister_device(&stm_heartbeat[i].data);
0098 fail_free:
0099         kfree(stm_heartbeat[i].data.name);
0100     }
0101 
0102     return ret;
0103 }
0104 
0105 static void stm_heartbeat_exit(void)
0106 {
0107     int i;
0108 
0109     for (i = 0; i < nr_devs; i++) {
0110         stm_source_unregister_device(&stm_heartbeat[i].data);
0111         kfree(stm_heartbeat[i].data.name);
0112     }
0113 }
0114 
0115 module_init(stm_heartbeat_init);
0116 module_exit(stm_heartbeat_exit);
0117 
0118 MODULE_LICENSE("GPL v2");
0119 MODULE_DESCRIPTION("stm_heartbeat driver");
0120 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");