2018-03-28 18:43:57 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-02-15 20:12:04 +03:00
/*
* Simple heartbeat STM source driver
* Copyright ( c ) 2016 , Intel Corporation .
*
* Heartbeat STM source will send repetitive messages over STM devices to a
* trace host .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/hrtimer.h>
# include <linux/slab.h>
# include <linux/stm.h>
# define STM_HEARTBEAT_MAX 32
static int nr_devs = 4 ;
static int interval_ms = 10 ;
2016-03-04 17:22:33 +03:00
module_param ( nr_devs , int , 0400 ) ;
2016-02-15 20:12:04 +03:00
module_param ( interval_ms , int , 0600 ) ;
static struct stm_heartbeat {
struct stm_source_data data ;
struct hrtimer hrtimer ;
unsigned int active ;
} stm_heartbeat [ STM_HEARTBEAT_MAX ] ;
static const char str [ ] = " heartbeat stm source driver is here to serve you " ;
static enum hrtimer_restart stm_heartbeat_hrtimer_handler ( struct hrtimer * hr )
{
struct stm_heartbeat * heartbeat = container_of ( hr , struct stm_heartbeat ,
hrtimer ) ;
stm_source_write ( & heartbeat - > data , 0 , str , sizeof str ) ;
if ( heartbeat - > active )
hrtimer_forward_now ( hr , ms_to_ktime ( interval_ms ) ) ;
return heartbeat - > active ? HRTIMER_RESTART : HRTIMER_NORESTART ;
}
static int stm_heartbeat_link ( struct stm_source_data * data )
{
struct stm_heartbeat * heartbeat =
container_of ( data , struct stm_heartbeat , data ) ;
heartbeat - > active = 1 ;
hrtimer_start ( & heartbeat - > hrtimer , ms_to_ktime ( interval_ms ) ,
HRTIMER_MODE_ABS ) ;
return 0 ;
}
static void stm_heartbeat_unlink ( struct stm_source_data * data )
{
struct stm_heartbeat * heartbeat =
container_of ( data , struct stm_heartbeat , data ) ;
heartbeat - > active = 0 ;
hrtimer_cancel ( & heartbeat - > hrtimer ) ;
}
static int stm_heartbeat_init ( void )
{
2021-01-15 22:59:16 +03:00
int i , ret ;
2016-02-15 20:12:04 +03:00
2016-03-04 17:22:33 +03:00
if ( nr_devs < 0 | | nr_devs > STM_HEARTBEAT_MAX )
2016-02-15 20:12:04 +03:00
return - EINVAL ;
2016-03-04 17:22:33 +03:00
for ( i = 0 ; i < nr_devs ; i + + ) {
2016-02-15 20:12:04 +03:00
stm_heartbeat [ i ] . data . name =
kasprintf ( GFP_KERNEL , " heartbeat.%d " , i ) ;
2021-01-15 22:59:16 +03:00
if ( ! stm_heartbeat [ i ] . data . name ) {
ret = - ENOMEM ;
2016-02-15 20:12:04 +03:00
goto fail_unregister ;
2021-01-15 22:59:16 +03:00
}
2016-02-15 20:12:04 +03:00
stm_heartbeat [ i ] . data . nr_chans = 1 ;
2018-10-05 15:43:04 +03:00
stm_heartbeat [ i ] . data . link = stm_heartbeat_link ;
2016-02-15 20:12:04 +03:00
stm_heartbeat [ i ] . data . unlink = stm_heartbeat_unlink ;
hrtimer_init ( & stm_heartbeat [ i ] . hrtimer , CLOCK_MONOTONIC ,
HRTIMER_MODE_ABS ) ;
stm_heartbeat [ i ] . hrtimer . function =
stm_heartbeat_hrtimer_handler ;
ret = stm_source_register_device ( NULL , & stm_heartbeat [ i ] . data ) ;
if ( ret )
goto fail_free ;
}
return 0 ;
fail_unregister :
for ( i - - ; i > = 0 ; i - - ) {
stm_source_unregister_device ( & stm_heartbeat [ i ] . data ) ;
fail_free :
kfree ( stm_heartbeat [ i ] . data . name ) ;
}
return ret ;
}
static void stm_heartbeat_exit ( void )
{
int i ;
2016-03-04 17:22:33 +03:00
for ( i = 0 ; i < nr_devs ; i + + ) {
2016-02-15 20:12:04 +03:00
stm_source_unregister_device ( & stm_heartbeat [ i ] . data ) ;
kfree ( stm_heartbeat [ i ] . data . name ) ;
}
}
module_init ( stm_heartbeat_init ) ;
module_exit ( stm_heartbeat_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " stm_heartbeat driver " ) ;
MODULE_AUTHOR ( " Alexander Shishkin <alexander.shishkin@linux.intel.com> " ) ;