Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/hw_random/timeriomem-rng.c
15111 views
1
/*
2
* drivers/char/hw_random/timeriomem-rng.c
3
*
4
* Copyright (C) 2009 Alexander Clouter <[email protected]>
5
*
6
* Derived from drivers/char/hw_random/omap-rng.c
7
* Copyright 2005 (c) MontaVista Software, Inc.
8
* Author: Deepak Saxena <[email protected]>
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License version 2 as
12
* published by the Free Software Foundation.
13
*
14
* Overview:
15
* This driver is useful for platforms that have an IO range that provides
16
* periodic random data from a single IO memory address. All the platform
17
* has to do is provide the address and 'wait time' that new data becomes
18
* available.
19
*
20
* TODO: add support for reading sizes other than 32bits and masking
21
*/
22
23
#include <linux/module.h>
24
#include <linux/kernel.h>
25
#include <linux/platform_device.h>
26
#include <linux/hw_random.h>
27
#include <linux/io.h>
28
#include <linux/timeriomem-rng.h>
29
#include <linux/jiffies.h>
30
#include <linux/sched.h>
31
#include <linux/timer.h>
32
#include <linux/completion.h>
33
34
static struct timeriomem_rng_data *timeriomem_rng_data;
35
36
static void timeriomem_rng_trigger(unsigned long);
37
static DEFINE_TIMER(timeriomem_rng_timer, timeriomem_rng_trigger, 0, 0);
38
39
/*
40
* have data return 1, however return 0 if we have nothing
41
*/
42
static int timeriomem_rng_data_present(struct hwrng *rng, int wait)
43
{
44
if (rng->priv == 0)
45
return 1;
46
47
if (!wait || timeriomem_rng_data->present)
48
return timeriomem_rng_data->present;
49
50
wait_for_completion(&timeriomem_rng_data->completion);
51
52
return 1;
53
}
54
55
static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)
56
{
57
unsigned long cur;
58
s32 delay;
59
60
*data = readl(timeriomem_rng_data->address);
61
62
if (rng->priv != 0) {
63
cur = jiffies;
64
65
delay = cur - timeriomem_rng_timer.expires;
66
delay = rng->priv - (delay % rng->priv);
67
68
timeriomem_rng_timer.expires = cur + delay;
69
timeriomem_rng_data->present = 0;
70
71
init_completion(&timeriomem_rng_data->completion);
72
add_timer(&timeriomem_rng_timer);
73
}
74
75
return 4;
76
}
77
78
static void timeriomem_rng_trigger(unsigned long dummy)
79
{
80
timeriomem_rng_data->present = 1;
81
complete(&timeriomem_rng_data->completion);
82
}
83
84
static struct hwrng timeriomem_rng_ops = {
85
.name = "timeriomem",
86
.data_present = timeriomem_rng_data_present,
87
.data_read = timeriomem_rng_data_read,
88
.priv = 0,
89
};
90
91
static int __devinit timeriomem_rng_probe(struct platform_device *pdev)
92
{
93
struct resource *res;
94
int ret;
95
96
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
97
98
if (!res)
99
return -ENOENT;
100
101
timeriomem_rng_data = pdev->dev.platform_data;
102
103
timeriomem_rng_data->address = ioremap(res->start,
104
res->end - res->start + 1);
105
if (!timeriomem_rng_data->address)
106
return -EIO;
107
108
if (timeriomem_rng_data->period != 0
109
&& usecs_to_jiffies(timeriomem_rng_data->period) > 0) {
110
timeriomem_rng_timer.expires = jiffies;
111
112
timeriomem_rng_ops.priv = usecs_to_jiffies(
113
timeriomem_rng_data->period);
114
}
115
timeriomem_rng_data->present = 1;
116
117
ret = hwrng_register(&timeriomem_rng_ops);
118
if (ret)
119
goto failed;
120
121
dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
122
timeriomem_rng_data->address,
123
timeriomem_rng_data->period);
124
125
return 0;
126
127
failed:
128
dev_err(&pdev->dev, "problem registering\n");
129
iounmap(timeriomem_rng_data->address);
130
131
return ret;
132
}
133
134
static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
135
{
136
del_timer_sync(&timeriomem_rng_timer);
137
hwrng_unregister(&timeriomem_rng_ops);
138
139
iounmap(timeriomem_rng_data->address);
140
141
return 0;
142
}
143
144
static struct platform_driver timeriomem_rng_driver = {
145
.driver = {
146
.name = "timeriomem_rng",
147
.owner = THIS_MODULE,
148
},
149
.probe = timeriomem_rng_probe,
150
.remove = __devexit_p(timeriomem_rng_remove),
151
};
152
153
static int __init timeriomem_rng_init(void)
154
{
155
return platform_driver_register(&timeriomem_rng_driver);
156
}
157
158
static void __exit timeriomem_rng_exit(void)
159
{
160
platform_driver_unregister(&timeriomem_rng_driver);
161
}
162
163
module_init(timeriomem_rng_init);
164
module_exit(timeriomem_rng_exit);
165
166
MODULE_LICENSE("GPL");
167
MODULE_AUTHOR("Alexander Clouter <[email protected]>");
168
MODULE_DESCRIPTION("Timer IOMEM H/W RNG driver");
169
170