xref: /openbmc/linux/drivers/char/ps3flash.c (revision 63dc02bd)
1 /*
2  * PS3 FLASH ROM Storage Driver
3  *
4  * Copyright (C) 2007 Sony Computer Entertainment Inc.
5  * Copyright 2007 Sony Corp.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <linux/fs.h>
22 #include <linux/miscdevice.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25 #include <linux/module.h>
26 
27 #include <asm/lv1call.h>
28 #include <asm/ps3stor.h>
29 
30 
31 #define DEVICE_NAME		"ps3flash"
32 
33 #define FLASH_BLOCK_SIZE	(256*1024)
34 
35 
36 struct ps3flash_private {
37 	struct mutex mutex;	/* Bounce buffer mutex */
38 	u64 chunk_sectors;
39 	int tag;		/* Start sector of buffer, -1 if invalid */
40 	bool dirty;
41 };
42 
43 static struct ps3_storage_device *ps3flash_dev;
44 
45 static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
46 				       u64 start_sector, int write)
47 {
48 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
49 	u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
50 					     start_sector, priv->chunk_sectors,
51 					     write);
52 	if (res) {
53 		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
54 			__LINE__, write ? "write" : "read", res);
55 		return -EIO;
56 	}
57 	return 0;
58 }
59 
60 static int ps3flash_writeback(struct ps3_storage_device *dev)
61 {
62 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
63 	int res;
64 
65 	if (!priv->dirty || priv->tag < 0)
66 		return 0;
67 
68 	res = ps3flash_read_write_sectors(dev, priv->tag, 1);
69 	if (res)
70 		return res;
71 
72 	priv->dirty = false;
73 	return 0;
74 }
75 
76 static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
77 {
78 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
79 	int res;
80 
81 	if (start_sector == priv->tag)
82 		return 0;
83 
84 	res = ps3flash_writeback(dev);
85 	if (res)
86 		return res;
87 
88 	priv->tag = -1;
89 
90 	res = ps3flash_read_write_sectors(dev, start_sector, 0);
91 	if (res)
92 		return res;
93 
94 	priv->tag = start_sector;
95 	return 0;
96 }
97 
98 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
99 {
100 	struct ps3_storage_device *dev = ps3flash_dev;
101 	loff_t res;
102 
103 	mutex_lock(&file->f_mapping->host->i_mutex);
104 	switch (origin) {
105 	case 0:
106 		break;
107 	case 1:
108 		offset += file->f_pos;
109 		break;
110 	case 2:
111 		offset += dev->regions[dev->region_idx].size*dev->blk_size;
112 		break;
113 	default:
114 		offset = -1;
115 	}
116 	if (offset < 0) {
117 		res = -EINVAL;
118 		goto out;
119 	}
120 
121 	file->f_pos = offset;
122 	res = file->f_pos;
123 
124 out:
125 	mutex_unlock(&file->f_mapping->host->i_mutex);
126 	return res;
127 }
128 
129 static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
130 			     size_t count, loff_t *pos)
131 {
132 	struct ps3_storage_device *dev = ps3flash_dev;
133 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
134 	u64 size, sector, offset;
135 	int res;
136 	size_t remaining, n;
137 	const void *src;
138 
139 	dev_dbg(&dev->sbd.core,
140 		"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
141 		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
142 
143 	size = dev->regions[dev->region_idx].size*dev->blk_size;
144 	if (*pos >= size || !count)
145 		return 0;
146 
147 	if (*pos + count > size) {
148 		dev_dbg(&dev->sbd.core,
149 			"%s:%u Truncating count from %zu to %llu\n", __func__,
150 			__LINE__, count, size - *pos);
151 		count = size - *pos;
152 	}
153 
154 	sector = *pos / dev->bounce_size * priv->chunk_sectors;
155 	offset = *pos % dev->bounce_size;
156 
157 	remaining = count;
158 	do {
159 		n = min_t(u64, remaining, dev->bounce_size - offset);
160 		src = dev->bounce_buf + offset;
161 
162 		mutex_lock(&priv->mutex);
163 
164 		res = ps3flash_fetch(dev, sector);
165 		if (res)
166 			goto fail;
167 
168 		dev_dbg(&dev->sbd.core,
169 			"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
170 			__func__, __LINE__, n, src, userbuf, kernelbuf);
171 		if (userbuf) {
172 			if (copy_to_user(userbuf, src, n)) {
173 				res = -EFAULT;
174 				goto fail;
175 			}
176 			userbuf += n;
177 		}
178 		if (kernelbuf) {
179 			memcpy(kernelbuf, src, n);
180 			kernelbuf += n;
181 		}
182 
183 		mutex_unlock(&priv->mutex);
184 
185 		*pos += n;
186 		remaining -= n;
187 		sector += priv->chunk_sectors;
188 		offset = 0;
189 	} while (remaining > 0);
190 
191 	return count;
192 
193 fail:
194 	mutex_unlock(&priv->mutex);
195 	return res;
196 }
197 
198 static ssize_t ps3flash_write(const char __user *userbuf,
199 			      const void *kernelbuf, size_t count, loff_t *pos)
200 {
201 	struct ps3_storage_device *dev = ps3flash_dev;
202 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
203 	u64 size, sector, offset;
204 	int res = 0;
205 	size_t remaining, n;
206 	void *dst;
207 
208 	dev_dbg(&dev->sbd.core,
209 		"%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
210 		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
211 
212 	size = dev->regions[dev->region_idx].size*dev->blk_size;
213 	if (*pos >= size || !count)
214 		return 0;
215 
216 	if (*pos + count > size) {
217 		dev_dbg(&dev->sbd.core,
218 			"%s:%u Truncating count from %zu to %llu\n", __func__,
219 			__LINE__, count, size - *pos);
220 		count = size - *pos;
221 	}
222 
223 	sector = *pos / dev->bounce_size * priv->chunk_sectors;
224 	offset = *pos % dev->bounce_size;
225 
226 	remaining = count;
227 	do {
228 		n = min_t(u64, remaining, dev->bounce_size - offset);
229 		dst = dev->bounce_buf + offset;
230 
231 		mutex_lock(&priv->mutex);
232 
233 		if (n != dev->bounce_size)
234 			res = ps3flash_fetch(dev, sector);
235 		else if (sector != priv->tag)
236 			res = ps3flash_writeback(dev);
237 		if (res)
238 			goto fail;
239 
240 		dev_dbg(&dev->sbd.core,
241 			"%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
242 			__func__, __LINE__, n, userbuf, kernelbuf, dst);
243 		if (userbuf) {
244 			if (copy_from_user(dst, userbuf, n)) {
245 				res = -EFAULT;
246 				goto fail;
247 			}
248 			userbuf += n;
249 		}
250 		if (kernelbuf) {
251 			memcpy(dst, kernelbuf, n);
252 			kernelbuf += n;
253 		}
254 
255 		priv->tag = sector;
256 		priv->dirty = true;
257 
258 		mutex_unlock(&priv->mutex);
259 
260 		*pos += n;
261 		remaining -= n;
262 		sector += priv->chunk_sectors;
263 		offset = 0;
264 	} while (remaining > 0);
265 
266 	return count;
267 
268 fail:
269 	mutex_unlock(&priv->mutex);
270 	return res;
271 }
272 
273 static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
274 				  size_t count, loff_t *pos)
275 {
276 	return ps3flash_read(buf, NULL, count, pos);
277 }
278 
279 static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
280 				   size_t count, loff_t *pos)
281 {
282 	return ps3flash_write(buf, NULL, count, pos);
283 }
284 
285 static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
286 {
287 	return ps3flash_read(NULL, buf, count, &pos);
288 }
289 
290 static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
291 				     loff_t pos)
292 {
293 	ssize_t res;
294 	int wb;
295 
296 	res = ps3flash_write(NULL, buf, count, &pos);
297 	if (res < 0)
298 		return res;
299 
300 	/* Make kernel writes synchronous */
301 	wb = ps3flash_writeback(ps3flash_dev);
302 	if (wb)
303 		return wb;
304 
305 	return res;
306 }
307 
308 static int ps3flash_flush(struct file *file, fl_owner_t id)
309 {
310 	return ps3flash_writeback(ps3flash_dev);
311 }
312 
313 static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync)
314 {
315 	struct inode *inode = file->f_path.dentry->d_inode;
316 	int err;
317 	mutex_lock(&inode->i_mutex);
318 	err = ps3flash_writeback(ps3flash_dev);
319 	mutex_unlock(&inode->i_mutex);
320 	return err;
321 }
322 
323 static irqreturn_t ps3flash_interrupt(int irq, void *data)
324 {
325 	struct ps3_storage_device *dev = data;
326 	int res;
327 	u64 tag, status;
328 
329 	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
330 
331 	if (tag != dev->tag)
332 		dev_err(&dev->sbd.core,
333 			"%s:%u: tag mismatch, got %llx, expected %llx\n",
334 			__func__, __LINE__, tag, dev->tag);
335 
336 	if (res) {
337 		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
338 			__func__, __LINE__, res, status);
339 	} else {
340 		dev->lv1_status = status;
341 		complete(&dev->done);
342 	}
343 	return IRQ_HANDLED;
344 }
345 
346 static const struct file_operations ps3flash_fops = {
347 	.owner	= THIS_MODULE,
348 	.llseek	= ps3flash_llseek,
349 	.read	= ps3flash_user_read,
350 	.write	= ps3flash_user_write,
351 	.flush	= ps3flash_flush,
352 	.fsync	= ps3flash_fsync,
353 };
354 
355 static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
356 	.read	= ps3flash_kernel_read,
357 	.write	= ps3flash_kernel_write,
358 };
359 
360 static struct miscdevice ps3flash_misc = {
361 	.minor	= MISC_DYNAMIC_MINOR,
362 	.name	= DEVICE_NAME,
363 	.fops	= &ps3flash_fops,
364 };
365 
366 static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
367 {
368 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
369 	struct ps3flash_private *priv;
370 	int error;
371 	unsigned long tmp;
372 
373 	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
374 	if (tmp % FLASH_BLOCK_SIZE) {
375 		dev_err(&dev->sbd.core,
376 			"%s:%u region start %lu is not aligned\n", __func__,
377 			__LINE__, tmp);
378 		return -EINVAL;
379 	}
380 	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
381 	if (tmp % FLASH_BLOCK_SIZE) {
382 		dev_err(&dev->sbd.core,
383 			"%s:%u region size %lu is not aligned\n", __func__,
384 			__LINE__, tmp);
385 		return -EINVAL;
386 	}
387 
388 	/* use static buffer, kmalloc cannot allocate 256 KiB */
389 	if (!ps3flash_bounce_buffer.address)
390 		return -ENODEV;
391 
392 	if (ps3flash_dev) {
393 		dev_err(&dev->sbd.core,
394 			"Only one FLASH device is supported\n");
395 		return -EBUSY;
396 	}
397 
398 	ps3flash_dev = dev;
399 
400 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
401 	if (!priv) {
402 		error = -ENOMEM;
403 		goto fail;
404 	}
405 
406 	ps3_system_bus_set_drvdata(&dev->sbd, priv);
407 	mutex_init(&priv->mutex);
408 	priv->tag = -1;
409 
410 	dev->bounce_size = ps3flash_bounce_buffer.size;
411 	dev->bounce_buf = ps3flash_bounce_buffer.address;
412 	priv->chunk_sectors = dev->bounce_size / dev->blk_size;
413 
414 	error = ps3stor_setup(dev, ps3flash_interrupt);
415 	if (error)
416 		goto fail_free_priv;
417 
418 	ps3flash_misc.parent = &dev->sbd.core;
419 	error = misc_register(&ps3flash_misc);
420 	if (error) {
421 		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
422 			__func__, __LINE__, error);
423 		goto fail_teardown;
424 	}
425 
426 	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
427 		 __func__, __LINE__, ps3flash_misc.minor);
428 
429 	ps3_os_area_flash_register(&ps3flash_kernel_ops);
430 	return 0;
431 
432 fail_teardown:
433 	ps3stor_teardown(dev);
434 fail_free_priv:
435 	kfree(priv);
436 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
437 fail:
438 	ps3flash_dev = NULL;
439 	return error;
440 }
441 
442 static int ps3flash_remove(struct ps3_system_bus_device *_dev)
443 {
444 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
445 
446 	ps3_os_area_flash_register(NULL);
447 	misc_deregister(&ps3flash_misc);
448 	ps3stor_teardown(dev);
449 	kfree(ps3_system_bus_get_drvdata(&dev->sbd));
450 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
451 	ps3flash_dev = NULL;
452 	return 0;
453 }
454 
455 
456 static struct ps3_system_bus_driver ps3flash = {
457 	.match_id	= PS3_MATCH_ID_STOR_FLASH,
458 	.core.name	= DEVICE_NAME,
459 	.core.owner	= THIS_MODULE,
460 	.probe		= ps3flash_probe,
461 	.remove		= ps3flash_remove,
462 	.shutdown	= ps3flash_remove,
463 };
464 
465 
466 static int __init ps3flash_init(void)
467 {
468 	return ps3_system_bus_driver_register(&ps3flash);
469 }
470 
471 static void __exit ps3flash_exit(void)
472 {
473 	ps3_system_bus_driver_unregister(&ps3flash);
474 }
475 
476 module_init(ps3flash_init);
477 module_exit(ps3flash_exit);
478 
479 MODULE_LICENSE("GPL");
480 MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
481 MODULE_AUTHOR("Sony Corporation");
482 MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
483