1 /*
2  	Hardware driver for the AMD 768/8111 Random Number Generator (RNG)
3 	(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
4 	(c) Copyright 2002,2003 Andi Kleen, SuSE Labs
5 
6  	derived from
7 
8 	Hardware driver for Intel i810 Random Number Generator (RNG)
9 	Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
10 	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
11 
12 	Please read Documentation/i810_rng.txt for details on use.
13 
14 	----------------------------------------------------------
15 	This software may be used and distributed according to the terms
16         of the GNU General Public License, incorporated herein by reference.
17 
18  */
19 
20 
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/fs.h>
24 #include <linux/init.h>
25 #include <linux/pci.h>
26 #include <linux/interrupt.h>
27 #include <linux/spinlock.h>
28 #include <linux/random.h>
29 #include <linux/miscdevice.h>
30 #include <linux/smp_lock.h>
31 #include <linux/mm.h>
32 #include <linux/delay.h>
33 
34 #include <asm/io.h>
35 #include <asm/uaccess.h>
36 
37 
38 /*
39  * core module and version information
40  */
41 #define RNG_VERSION "0.1.0"
42 #define RNG_MODULE_NAME "amd768_rng"
43 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
44 #define PFX RNG_MODULE_NAME ": "
45 
46 
47 /*
48  * debugging macros
49  */
50 #undef RNG_DEBUG /* define to enable copious debugging info */
51 
52 #ifdef RNG_DEBUG
53 /* note: prints function name for you */
54 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
55 #else
56 #define DPRINTK(fmt, args...)
57 #endif
58 
59 #undef RNG_NDEBUG        /* define to disable lightweight runtime checks */
60 #ifdef RNG_NDEBUG
61 #define assert(expr)
62 #else
63 #define assert(expr) \
64         if(!(expr)) {                                   \
65         printk( "Assertion failed! %s,%s,%s,line=%d\n", \
66         #expr,__FILE__,__FUNCTION__,__LINE__);          \
67         }
68 #endif
69 
70 #define RNG_MISCDEV_MINOR		183 /* official */
71 
72 /*
73  * various RNG status variables.  they are globals
74  * as we only support a single RNG device
75  */
76 
77 static u32 pmbase;			/* PMxx I/O base */
78 static struct semaphore rng_open_sem;	/* Semaphore for serializing rng_open/release */
79 
80 
81 /*
82  * inlined helper functions for accessing RNG registers
83  */
84 
rng_data_present(void)85 static inline int rng_data_present (void)
86 {
87       	return inl(pmbase+0xF4) & 1;
88 }
89 
90 
rng_data_read(void)91 static inline int rng_data_read (void)
92 {
93 	return inl(pmbase+0xF0);
94 }
95 
rng_dev_open(struct inode * inode,struct file * filp)96 static int rng_dev_open (struct inode *inode, struct file *filp)
97 {
98 	if ((filp->f_mode & FMODE_READ) == 0)
99 		return -EINVAL;
100 	if (filp->f_mode & FMODE_WRITE)
101 		return -EINVAL;
102 
103 	/* wait for device to become free */
104 	if (filp->f_flags & O_NONBLOCK) {
105 		if (down_trylock (&rng_open_sem))
106 			return -EAGAIN;
107 	} else {
108 		if (down_interruptible (&rng_open_sem))
109 			return -ERESTARTSYS;
110 	}
111 	return 0;
112 }
113 
114 
rng_dev_release(struct inode * inode,struct file * filp)115 static int rng_dev_release (struct inode *inode, struct file *filp)
116 {
117 	up(&rng_open_sem);
118 	return 0;
119 }
120 
121 
rng_dev_read(struct file * filp,char * buf,size_t size,loff_t * offp)122 static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
123 			     loff_t * offp)
124 {
125 	static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED;
126 	int have_data;
127 	u32 data = 0;
128 	ssize_t ret = 0;
129 
130 	while (size) {
131 		spin_lock(&rng_lock);
132 
133 		have_data = 0;
134 		if (rng_data_present()) {
135 			data = rng_data_read();
136 			have_data = 4;
137 		}
138 
139 		spin_unlock (&rng_lock);
140 
141 		while (have_data > 0) {
142 			if (put_user((u8)data, buf++)) {
143 				ret = ret ? : -EFAULT;
144 				break;
145 			}
146 			size--;
147 			ret++;
148 			have_data--;
149 			data>>=8;
150 		}
151 
152 		if (filp->f_flags & O_NONBLOCK)
153 			return ret ? : -EAGAIN;
154 
155 		if(current->need_resched)
156 		{
157 			current->state = TASK_INTERRUPTIBLE;
158 			schedule_timeout(1);
159 		}
160 		else
161 			udelay(200);	/* FIXME: We could poll for 250uS ?? */
162 
163 		if (signal_pending (current))
164 			return ret ? : -ERESTARTSYS;
165 	}
166 	return ret;
167 }
168 
169 
170 static struct file_operations rng_chrdev_ops = {
171 	owner:		THIS_MODULE,
172 	open:		rng_dev_open,
173 	release:	rng_dev_release,
174 	read:		rng_dev_read,
175 };
176 
177 
178 static struct miscdevice rng_miscdev = {
179 	RNG_MISCDEV_MINOR,
180 	RNG_MODULE_NAME,
181 	&rng_chrdev_ops,
182 };
183 
184 
185 /*
186  * rng_init_one - look for and attempt to init a single RNG
187  */
rng_init_one(struct pci_dev * dev)188 static int __init rng_init_one (struct pci_dev *dev)
189 {
190 	int rc;
191 	u8 rnen;
192 
193 	DPRINTK ("ENTER\n");
194 
195 	rc = misc_register (&rng_miscdev);
196 	if (rc) {
197 		printk (KERN_ERR PFX "cannot register misc device\n");
198 		DPRINTK ("EXIT, returning %d\n", rc);
199 		goto err_out;
200 	}
201 
202 	pci_read_config_dword(dev, 0x58, &pmbase);
203 
204 	pmbase&=0x0000FF00;
205 
206 	if(pmbase == 0)
207 	{
208 		printk (KERN_ERR PFX "power management base not set\n");
209 		DPRINTK ("EXIT, returning %d\n", rc);
210 		goto err_out_free_miscdev;
211 	}
212 
213 	pci_read_config_byte(dev, 0x40, &rnen);
214 	rnen|=(1<<7);	/* RNG on */
215 	pci_write_config_byte(dev, 0x40, rnen);
216 
217 	pci_read_config_byte(dev, 0x41, &rnen);
218 	rnen|=(1<<7);	/* PMIO enable */
219 	pci_write_config_byte(dev, 0x41, rnen);
220 
221 	printk(KERN_INFO PFX "AMD768 system management I/O registers at 0x%X.\n", pmbase);
222 	DPRINTK ("EXIT, returning 0\n");
223 	return 0;
224 
225 err_out_free_miscdev:
226 	misc_deregister (&rng_miscdev);
227 err_out:
228 	return rc;
229 }
230 
231 
232 /*
233  * Data for PCI driver interface
234  *
235  * This data only exists for exporting the supported
236  * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
237  * register a pci_driver, because someone else might one day
238  * want to register another driver on the same PCI id.
239  */
240 static struct pci_device_id rng_pci_tbl[] __initdata = {
241 	{ 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, },
242 	{ 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, },
243 	{ 0, },
244 };
245 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
246 
247 
248 MODULE_AUTHOR("Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek, Andi Kleen");
249 MODULE_DESCRIPTION("AMD 768/8111 Random Number Generator (RNG) driver");
250 MODULE_LICENSE("GPL");
251 
252 
253 /*
254  * rng_init - initialize RNG module
255  */
rng_init(void)256 static int __init rng_init (void)
257 {
258 	int rc;
259 	struct pci_dev *pdev;
260 
261 	DPRINTK ("ENTER\n");
262 
263 	init_MUTEX (&rng_open_sem);
264 
265 	pci_for_each_dev(pdev) {
266 		if (pci_match_device (rng_pci_tbl, pdev) != NULL)
267 			goto match;
268 	}
269 
270 	DPRINTK ("EXIT, returning -ENODEV\n");
271 	return -ENODEV;
272 
273 match:
274 	rc = rng_init_one (pdev);
275 	if (rc)
276 		return rc;
277 
278 	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
279 
280 	DPRINTK ("EXIT, returning 0\n");
281 	return 0;
282 }
283 
284 
285 /*
286  * rng_init - shutdown RNG module
287  */
rng_cleanup(void)288 static void __exit rng_cleanup (void)
289 {
290 	DPRINTK ("ENTER\n");
291 	misc_deregister (&rng_miscdev);
292 	DPRINTK ("EXIT\n");
293 }
294 
295 
296 module_init (rng_init);
297 module_exit (rng_cleanup);
298