• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Tilera Corporation. All Rights Reserved.
3  *
4  *   This program is free software; you can redistribute it and/or
5  *   modify it under the terms of the GNU General Public License
6  *   as published by the Free Software Foundation, version 2.
7  *
8  *   This program is distributed in the hope that it will be useful, but
9  *   WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11  *   NON INFRINGEMENT.  See the GNU General Public License for
12  *   more details.
13  *
14  * SPI Flash ROM driver
15  *
16  * This source code is derived from code provided in "Linux Device
17  * Drivers, Third Edition", by Jonathan Corbet, Alessandro Rubini, and
18  * Greg Kroah-Hartman, published by O'Reilly Media, Inc.
19  */
20 
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/kernel.h>	/* printk() */
24 #include <linux/slab.h>		/* kmalloc() */
25 #include <linux/fs.h>		/* everything... */
26 #include <linux/errno.h>	/* error codes */
27 #include <linux/types.h>	/* size_t */
28 #include <linux/proc_fs.h>
29 #include <linux/fcntl.h>	/* O_ACCMODE */
30 #include <linux/aio.h>
31 #include <linux/pagemap.h>
32 #include <linux/hugetlb.h>
33 #include <linux/uaccess.h>
34 #include <linux/platform_device.h>
35 #include <hv/hypervisor.h>
36 #include <linux/ioctl.h>
37 #include <linux/cdev.h>
38 #include <linux/delay.h>
39 #include <hv/drv_srom_intf.h>
40 
41 /*
42  * Size of our hypervisor I/O requests.  We break up large transfers
43  * so that we don't spend large uninterrupted spans of time in the
44  * hypervisor.  Erasing an SROM sector takes a significant fraction of
45  * a second, so if we allowed the user to, say, do one I/O to write the
46  * entire ROM, we'd get soft lockup timeouts, or worse.
47  */
48 #define SROM_CHUNK_SIZE ((size_t)4096)
49 
50 /*
51  * When hypervisor is busy (e.g. erasing), poll the status periodically.
52  */
53 
54 /*
55  * Interval to poll the state in msec
56  */
57 #define SROM_WAIT_TRY_INTERVAL 20
58 
59 /*
60  * Maximum times to poll the state
61  */
62 #define SROM_MAX_WAIT_TRY_TIMES 1000
63 
64 struct srom_dev {
65 	int hv_devhdl;			/* Handle for hypervisor device */
66 	u32 total_size;			/* Size of this device */
67 	u32 sector_size;		/* Size of a sector */
68 	u32 page_size;			/* Size of a page */
69 	struct mutex lock;		/* Allow only one accessor at a time */
70 };
71 
72 static int srom_major;			/* Dynamic major by default */
73 module_param(srom_major, int, 0);
74 MODULE_AUTHOR("Tilera Corporation");
75 MODULE_LICENSE("GPL");
76 
77 static int srom_devs;			/* Number of SROM partitions */
78 static struct cdev srom_cdev;
79 static struct platform_device *srom_parent;
80 static struct class *srom_class;
81 static struct srom_dev *srom_devices;
82 
83 /*
84  * Handle calling the hypervisor and managing EAGAIN/EBUSY.
85  */
86 
_srom_read(int hv_devhdl,void * buf,loff_t off,size_t count)87 static ssize_t _srom_read(int hv_devhdl, void *buf,
88 			  loff_t off, size_t count)
89 {
90 	int retval, retries = SROM_MAX_WAIT_TRY_TIMES;
91 	for (;;) {
92 		retval = hv_dev_pread(hv_devhdl, 0, (HV_VirtAddr)buf,
93 				      count, off);
94 		if (retval >= 0)
95 			return retval;
96 		if (retval == HV_EAGAIN)
97 			continue;
98 		if (retval == HV_EBUSY && --retries > 0) {
99 			msleep(SROM_WAIT_TRY_INTERVAL);
100 			continue;
101 		}
102 		pr_err("_srom_read: error %d\n", retval);
103 		return -EIO;
104 	}
105 }
106 
_srom_write(int hv_devhdl,const void * buf,loff_t off,size_t count)107 static ssize_t _srom_write(int hv_devhdl, const void *buf,
108 			   loff_t off, size_t count)
109 {
110 	int retval, retries = SROM_MAX_WAIT_TRY_TIMES;
111 	for (;;) {
112 		retval = hv_dev_pwrite(hv_devhdl, 0, (HV_VirtAddr)buf,
113 				       count, off);
114 		if (retval >= 0)
115 			return retval;
116 		if (retval == HV_EAGAIN)
117 			continue;
118 		if (retval == HV_EBUSY && --retries > 0) {
119 			msleep(SROM_WAIT_TRY_INTERVAL);
120 			continue;
121 		}
122 		pr_err("_srom_write: error %d\n", retval);
123 		return -EIO;
124 	}
125 }
126 
127 /**
128  * srom_open() - Device open routine.
129  * @inode: Inode for this device.
130  * @filp: File for this specific open of the device.
131  *
132  * Returns zero, or an error code.
133  */
srom_open(struct inode * inode,struct file * filp)134 static int srom_open(struct inode *inode, struct file *filp)
135 {
136 	filp->private_data = &srom_devices[iminor(inode)];
137 	return 0;
138 }
139 
140 
141 /**
142  * srom_release() - Device release routine.
143  * @inode: Inode for this device.
144  * @filp: File for this specific open of the device.
145  *
146  * Returns zero, or an error code.
147  */
srom_release(struct inode * inode,struct file * filp)148 static int srom_release(struct inode *inode, struct file *filp)
149 {
150 	struct srom_dev *srom = filp->private_data;
151 	char dummy;
152 
153 	/* Make sure we've flushed anything written to the ROM. */
154 	mutex_lock(&srom->lock);
155 	if (srom->hv_devhdl >= 0)
156 		_srom_write(srom->hv_devhdl, &dummy, SROM_FLUSH_OFF, 1);
157 	mutex_unlock(&srom->lock);
158 
159 	filp->private_data = NULL;
160 
161 	return 0;
162 }
163 
164 
165 /**
166  * srom_read() - Read data from the device.
167  * @filp: File for this specific open of the device.
168  * @buf: User's data buffer.
169  * @count: Number of bytes requested.
170  * @f_pos: File position.
171  *
172  * Returns number of bytes read, or an error code.
173  */
srom_read(struct file * filp,char __user * buf,size_t count,loff_t * f_pos)174 static ssize_t srom_read(struct file *filp, char __user *buf,
175 			 size_t count, loff_t *f_pos)
176 {
177 	int retval = 0;
178 	void *kernbuf;
179 	struct srom_dev *srom = filp->private_data;
180 
181 	kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL);
182 	if (!kernbuf)
183 		return -ENOMEM;
184 
185 	if (mutex_lock_interruptible(&srom->lock)) {
186 		retval = -ERESTARTSYS;
187 		kfree(kernbuf);
188 		return retval;
189 	}
190 
191 	while (count) {
192 		int hv_retval;
193 		int bytes_this_pass = min(count, SROM_CHUNK_SIZE);
194 
195 		hv_retval = _srom_read(srom->hv_devhdl, kernbuf,
196 				       *f_pos, bytes_this_pass);
197 		if (hv_retval <= 0) {
198 			if (retval == 0)
199 				retval = hv_retval;
200 			break;
201 		}
202 
203 		if (copy_to_user(buf, kernbuf, hv_retval) != 0) {
204 			retval = -EFAULT;
205 			break;
206 		}
207 
208 		retval += hv_retval;
209 		*f_pos += hv_retval;
210 		buf += hv_retval;
211 		count -= hv_retval;
212 	}
213 
214 	mutex_unlock(&srom->lock);
215 	kfree(kernbuf);
216 
217 	return retval;
218 }
219 
220 /**
221  * srom_write() - Write data to the device.
222  * @filp: File for this specific open of the device.
223  * @buf: User's data buffer.
224  * @count: Number of bytes requested.
225  * @f_pos: File position.
226  *
227  * Returns number of bytes written, or an error code.
228  */
srom_write(struct file * filp,const char __user * buf,size_t count,loff_t * f_pos)229 static ssize_t srom_write(struct file *filp, const char __user *buf,
230 			  size_t count, loff_t *f_pos)
231 {
232 	int retval = 0;
233 	void *kernbuf;
234 	struct srom_dev *srom = filp->private_data;
235 
236 	kernbuf = kmalloc(SROM_CHUNK_SIZE, GFP_KERNEL);
237 	if (!kernbuf)
238 		return -ENOMEM;
239 
240 	if (mutex_lock_interruptible(&srom->lock)) {
241 		retval = -ERESTARTSYS;
242 		kfree(kernbuf);
243 		return retval;
244 	}
245 
246 	while (count) {
247 		int hv_retval;
248 		int bytes_this_pass = min(count, SROM_CHUNK_SIZE);
249 
250 		if (copy_from_user(kernbuf, buf, bytes_this_pass) != 0) {
251 			retval = -EFAULT;
252 			break;
253 		}
254 
255 		hv_retval = _srom_write(srom->hv_devhdl, kernbuf,
256 					*f_pos, bytes_this_pass);
257 		if (hv_retval <= 0) {
258 			if (retval == 0)
259 				retval = hv_retval;
260 			break;
261 		}
262 
263 		retval += hv_retval;
264 		*f_pos += hv_retval;
265 		buf += hv_retval;
266 		count -= hv_retval;
267 	}
268 
269 	mutex_unlock(&srom->lock);
270 	kfree(kernbuf);
271 
272 	return retval;
273 }
274 
275 /* Provide our own implementation so we can use srom->total_size. */
srom_llseek(struct file * file,loff_t offset,int origin)276 loff_t srom_llseek(struct file *file, loff_t offset, int origin)
277 {
278 	struct srom_dev *srom = file->private_data;
279 	return fixed_size_llseek(file, offset, origin, srom->total_size);
280 }
281 
total_size_show(struct device * dev,struct device_attribute * attr,char * buf)282 static ssize_t total_size_show(struct device *dev,
283 			       struct device_attribute *attr, char *buf)
284 {
285 	struct srom_dev *srom = dev_get_drvdata(dev);
286 	return sprintf(buf, "%u\n", srom->total_size);
287 }
288 static DEVICE_ATTR_RO(total_size);
289 
sector_size_show(struct device * dev,struct device_attribute * attr,char * buf)290 static ssize_t sector_size_show(struct device *dev,
291 				struct device_attribute *attr, char *buf)
292 {
293 	struct srom_dev *srom = dev_get_drvdata(dev);
294 	return sprintf(buf, "%u\n", srom->sector_size);
295 }
296 static DEVICE_ATTR_RO(sector_size);
297 
page_size_show(struct device * dev,struct device_attribute * attr,char * buf)298 static ssize_t page_size_show(struct device *dev,
299 			      struct device_attribute *attr, char *buf)
300 {
301 	struct srom_dev *srom = dev_get_drvdata(dev);
302 	return sprintf(buf, "%u\n", srom->page_size);
303 }
304 static DEVICE_ATTR_RO(page_size);
305 
306 static struct attribute *srom_dev_attrs[] = {
307 	&dev_attr_total_size.attr,
308 	&dev_attr_sector_size.attr,
309 	&dev_attr_page_size.attr,
310 	NULL,
311 };
312 ATTRIBUTE_GROUPS(srom_dev);
313 
srom_devnode(struct device * dev,umode_t * mode)314 static char *srom_devnode(struct device *dev, umode_t *mode)
315 {
316 	*mode = S_IRUGO | S_IWUSR;
317 	return kasprintf(GFP_KERNEL, "srom/%s", dev_name(dev));
318 }
319 
320 /*
321  * The fops
322  */
323 static const struct file_operations srom_fops = {
324 	.owner =     THIS_MODULE,
325 	.llseek =    srom_llseek,
326 	.read =	     srom_read,
327 	.write =     srom_write,
328 	.open =	     srom_open,
329 	.release =   srom_release,
330 };
331 
332 /**
333  * srom_setup_minor() - Initialize per-minor information.
334  * @srom: Per-device SROM state.
335  * @index: Device to set up.
336  */
srom_setup_minor(struct srom_dev * srom,int index)337 static int srom_setup_minor(struct srom_dev *srom, int index)
338 {
339 	struct device *dev;
340 	int devhdl = srom->hv_devhdl;
341 
342 	mutex_init(&srom->lock);
343 
344 	if (_srom_read(devhdl, &srom->total_size,
345 		       SROM_TOTAL_SIZE_OFF, sizeof(srom->total_size)) < 0)
346 		return -EIO;
347 	if (_srom_read(devhdl, &srom->sector_size,
348 		       SROM_SECTOR_SIZE_OFF, sizeof(srom->sector_size)) < 0)
349 		return -EIO;
350 	if (_srom_read(devhdl, &srom->page_size,
351 		       SROM_PAGE_SIZE_OFF, sizeof(srom->page_size)) < 0)
352 		return -EIO;
353 
354 	dev = device_create(srom_class, &srom_parent->dev,
355 			    MKDEV(srom_major, index), srom, "%d", index);
356 	return PTR_ERR_OR_ZERO(dev);
357 }
358 
359 /** srom_init() - Initialize the driver's module. */
srom_init(void)360 static int srom_init(void)
361 {
362 	int result, i;
363 	dev_t dev = MKDEV(srom_major, 0);
364 
365 	/*
366 	 * Start with a plausible number of partitions; the krealloc() call
367 	 * below will yield about log(srom_devs) additional allocations.
368 	 */
369 	srom_devices = kzalloc(4 * sizeof(struct srom_dev), GFP_KERNEL);
370 
371 	/* Discover the number of srom partitions. */
372 	for (i = 0; ; i++) {
373 		int devhdl;
374 		char buf[20];
375 		struct srom_dev *new_srom_devices =
376 			krealloc(srom_devices, (i+1) * sizeof(struct srom_dev),
377 				 GFP_KERNEL | __GFP_ZERO);
378 		if (!new_srom_devices) {
379 			result = -ENOMEM;
380 			goto fail_mem;
381 		}
382 		srom_devices = new_srom_devices;
383 		sprintf(buf, "srom/0/%d", i);
384 		devhdl = hv_dev_open((HV_VirtAddr)buf, 0);
385 		if (devhdl < 0) {
386 			if (devhdl != HV_ENODEV)
387 				pr_notice("srom/%d: hv_dev_open failed: %d.\n",
388 					  i, devhdl);
389 			break;
390 		}
391 		srom_devices[i].hv_devhdl = devhdl;
392 	}
393 	srom_devs = i;
394 
395 	/* Bail out early if we have no partitions at all. */
396 	if (srom_devs == 0) {
397 		result = -ENODEV;
398 		goto fail_mem;
399 	}
400 
401 	/* Register our major, and accept a dynamic number. */
402 	if (srom_major)
403 		result = register_chrdev_region(dev, srom_devs, "srom");
404 	else {
405 		result = alloc_chrdev_region(&dev, 0, srom_devs, "srom");
406 		srom_major = MAJOR(dev);
407 	}
408 	if (result < 0)
409 		goto fail_mem;
410 
411 	/* Register a character device. */
412 	cdev_init(&srom_cdev, &srom_fops);
413 	srom_cdev.owner = THIS_MODULE;
414 	srom_cdev.ops = &srom_fops;
415 	result = cdev_add(&srom_cdev, dev, srom_devs);
416 	if (result < 0)
417 		goto fail_chrdev;
418 
419 	/* Create a parent device */
420 	srom_parent = platform_device_register_simple("srom", -1, NULL, 0);
421 	if (IS_ERR(srom_parent)) {
422 		result = PTR_ERR(srom_parent);
423 		goto fail_pdev;
424 	}
425 
426 	/* Create a sysfs class. */
427 	srom_class = class_create(THIS_MODULE, "srom");
428 	if (IS_ERR(srom_class)) {
429 		result = PTR_ERR(srom_class);
430 		goto fail_cdev;
431 	}
432 	srom_class->dev_groups = srom_dev_groups;
433 	srom_class->devnode = srom_devnode;
434 
435 	/* Do per-partition initialization */
436 	for (i = 0; i < srom_devs; i++) {
437 		result = srom_setup_minor(srom_devices + i, i);
438 		if (result < 0)
439 			goto fail_class;
440 	}
441 
442 	return 0;
443 
444 fail_class:
445 	for (i = 0; i < srom_devs; i++)
446 		device_destroy(srom_class, MKDEV(srom_major, i));
447 	class_destroy(srom_class);
448 fail_cdev:
449 	platform_device_unregister(srom_parent);
450 fail_pdev:
451 	cdev_del(&srom_cdev);
452 fail_chrdev:
453 	unregister_chrdev_region(dev, srom_devs);
454 fail_mem:
455 	kfree(srom_devices);
456 	return result;
457 }
458 
459 /** srom_cleanup() - Clean up the driver's module. */
srom_cleanup(void)460 static void srom_cleanup(void)
461 {
462 	int i;
463 	for (i = 0; i < srom_devs; i++)
464 		device_destroy(srom_class, MKDEV(srom_major, i));
465 	class_destroy(srom_class);
466 	cdev_del(&srom_cdev);
467 	platform_device_unregister(srom_parent);
468 	unregister_chrdev_region(MKDEV(srom_major, 0), srom_devs);
469 	kfree(srom_devices);
470 }
471 
472 module_init(srom_init);
473 module_exit(srom_cleanup);
474