cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iio-trig-hrtimer.c (5219B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * The industrial I/O periodic hrtimer trigger driver
      4 *
      5 * Copyright (C) Intuitive Aerial AB
      6 * Written by Marten Svanfeldt, marten@intuitiveaerial.com
      7 * Copyright (C) 2012, Analog Devices Inc.
      8 *	Author: Lars-Peter Clausen <lars@metafoo.de>
      9 * Copyright (C) 2015, Intel Corporation
     10 */
     11#include <linux/kernel.h>
     12#include <linux/slab.h>
     13#include <linux/hrtimer.h>
     14
     15#include <linux/iio/iio.h>
     16#include <linux/iio/trigger.h>
     17#include <linux/iio/sw_trigger.h>
     18
     19/* Defined locally, not in time64.h yet. */
     20#define PSEC_PER_SEC   1000000000000LL
     21
     22/* default sampling frequency - 100Hz */
     23#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100
     24
     25struct iio_hrtimer_info {
     26	struct iio_sw_trigger swt;
     27	struct hrtimer timer;
     28	int sampling_frequency[2];
     29	ktime_t period;
     30};
     31
     32static const struct config_item_type iio_hrtimer_type = {
     33	.ct_owner = THIS_MODULE,
     34};
     35
     36static
     37ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev,
     38					    struct device_attribute *attr,
     39					    char *buf)
     40{
     41	struct iio_trigger *trig = to_iio_trigger(dev);
     42	struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
     43
     44	return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO,
     45			ARRAY_SIZE(info->sampling_frequency),
     46			info->sampling_frequency);
     47}
     48
     49static
     50ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev,
     51					     struct device_attribute *attr,
     52					     const char *buf, size_t len)
     53{
     54	struct iio_trigger *trig = to_iio_trigger(dev);
     55	struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
     56	unsigned long long val;
     57	u64 period;
     58	int integer, fract, ret;
     59
     60	ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
     61	if (ret)
     62		return ret;
     63	if (integer < 0 || fract < 0)
     64		return -ERANGE;
     65
     66	val = fract + 1000ULL * integer;  /* mHz */
     67
     68	if (!val || val > UINT_MAX)
     69		return -EINVAL;
     70
     71	info->sampling_frequency[0] = integer;  /* Hz */
     72	info->sampling_frequency[1] = fract * 1000;  /* uHz */
     73	period = PSEC_PER_SEC;
     74	do_div(period, val);
     75	info->period = period;  /* nS */
     76
     77	return len;
     78}
     79
     80static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR,
     81		   iio_hrtimer_show_sampling_frequency,
     82		   iio_hrtimer_store_sampling_frequency);
     83
     84static struct attribute *iio_hrtimer_attrs[] = {
     85	&dev_attr_sampling_frequency.attr,
     86	NULL
     87};
     88
     89static const struct attribute_group iio_hrtimer_attr_group = {
     90	.attrs = iio_hrtimer_attrs,
     91};
     92
     93static const struct attribute_group *iio_hrtimer_attr_groups[] = {
     94	&iio_hrtimer_attr_group,
     95	NULL
     96};
     97
     98static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer)
     99{
    100	struct iio_hrtimer_info *info;
    101
    102	info = container_of(timer, struct iio_hrtimer_info, timer);
    103
    104	hrtimer_forward_now(timer, info->period);
    105	iio_trigger_poll(info->swt.trigger);
    106
    107	return HRTIMER_RESTART;
    108}
    109
    110static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state)
    111{
    112	struct iio_hrtimer_info *trig_info;
    113
    114	trig_info = iio_trigger_get_drvdata(trig);
    115
    116	if (state)
    117		hrtimer_start(&trig_info->timer, trig_info->period,
    118			      HRTIMER_MODE_REL_HARD);
    119	else
    120		hrtimer_cancel(&trig_info->timer);
    121
    122	return 0;
    123}
    124
    125static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
    126	.set_trigger_state = iio_trig_hrtimer_set_state,
    127};
    128
    129static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
    130{
    131	struct iio_hrtimer_info *trig_info;
    132	int ret;
    133
    134	trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
    135	if (!trig_info)
    136		return ERR_PTR(-ENOMEM);
    137
    138	trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name);
    139	if (!trig_info->swt.trigger) {
    140		ret = -ENOMEM;
    141		goto err_free_trig_info;
    142	}
    143
    144	iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
    145	trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops;
    146	trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups;
    147
    148	hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
    149	trig_info->timer.function = iio_hrtimer_trig_handler;
    150
    151	trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
    152	trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0];
    153
    154	ret = iio_trigger_register(trig_info->swt.trigger);
    155	if (ret)
    156		goto err_free_trigger;
    157
    158	iio_swt_group_init_type_name(&trig_info->swt, name, &iio_hrtimer_type);
    159	return &trig_info->swt;
    160err_free_trigger:
    161	iio_trigger_free(trig_info->swt.trigger);
    162err_free_trig_info:
    163	kfree(trig_info);
    164
    165	return ERR_PTR(ret);
    166}
    167
    168static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
    169{
    170	struct iio_hrtimer_info *trig_info;
    171
    172	trig_info = iio_trigger_get_drvdata(swt->trigger);
    173
    174	iio_trigger_unregister(swt->trigger);
    175
    176	/* cancel the timer after unreg to make sure no one rearms it */
    177	hrtimer_cancel(&trig_info->timer);
    178	iio_trigger_free(swt->trigger);
    179	kfree(trig_info);
    180
    181	return 0;
    182}
    183
    184static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = {
    185	.probe		= iio_trig_hrtimer_probe,
    186	.remove		= iio_trig_hrtimer_remove,
    187};
    188
    189static struct iio_sw_trigger_type iio_trig_hrtimer = {
    190	.name = "hrtimer",
    191	.owner = THIS_MODULE,
    192	.ops = &iio_trig_hrtimer_ops,
    193};
    194
    195module_iio_sw_trigger_driver(iio_trig_hrtimer);
    196
    197MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>");
    198MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
    199MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem");
    200MODULE_LICENSE("GPL v2");