xref: /openbmc/linux/drivers/char/ps3flash.c (revision db181ce0)
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 	return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
102 			dev->regions[dev->region_idx].size*dev->blk_size);
103 }
104 
105 static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
106 			     size_t count, loff_t *pos)
107 {
108 	struct ps3_storage_device *dev = ps3flash_dev;
109 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
110 	u64 size, sector, offset;
111 	int res;
112 	size_t remaining, n;
113 	const void *src;
114 
115 	dev_dbg(&dev->sbd.core,
116 		"%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
117 		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
118 
119 	size = dev->regions[dev->region_idx].size*dev->blk_size;
120 	if (*pos >= size || !count)
121 		return 0;
122 
123 	if (*pos + count > size) {
124 		dev_dbg(&dev->sbd.core,
125 			"%s:%u Truncating count from %zu to %llu\n", __func__,
126 			__LINE__, count, size - *pos);
127 		count = size - *pos;
128 	}
129 
130 	sector = *pos / dev->bounce_size * priv->chunk_sectors;
131 	offset = *pos % dev->bounce_size;
132 
133 	remaining = count;
134 	do {
135 		n = min_t(u64, remaining, dev->bounce_size - offset);
136 		src = dev->bounce_buf + offset;
137 
138 		mutex_lock(&priv->mutex);
139 
140 		res = ps3flash_fetch(dev, sector);
141 		if (res)
142 			goto fail;
143 
144 		dev_dbg(&dev->sbd.core,
145 			"%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
146 			__func__, __LINE__, n, src, userbuf, kernelbuf);
147 		if (userbuf) {
148 			if (copy_to_user(userbuf, src, n)) {
149 				res = -EFAULT;
150 				goto fail;
151 			}
152 			userbuf += n;
153 		}
154 		if (kernelbuf) {
155 			memcpy(kernelbuf, src, n);
156 			kernelbuf += n;
157 		}
158 
159 		mutex_unlock(&priv->mutex);
160 
161 		*pos += n;
162 		remaining -= n;
163 		sector += priv->chunk_sectors;
164 		offset = 0;
165 	} while (remaining > 0);
166 
167 	return count;
168 
169 fail:
170 	mutex_unlock(&priv->mutex);
171 	return res;
172 }
173 
174 static ssize_t ps3flash_write(const char __user *userbuf,
175 			      const void *kernelbuf, size_t count, loff_t *pos)
176 {
177 	struct ps3_storage_device *dev = ps3flash_dev;
178 	struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
179 	u64 size, sector, offset;
180 	int res = 0;
181 	size_t remaining, n;
182 	void *dst;
183 
184 	dev_dbg(&dev->sbd.core,
185 		"%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
186 		__func__, __LINE__, count, *pos, userbuf, kernelbuf);
187 
188 	size = dev->regions[dev->region_idx].size*dev->blk_size;
189 	if (*pos >= size || !count)
190 		return 0;
191 
192 	if (*pos + count > size) {
193 		dev_dbg(&dev->sbd.core,
194 			"%s:%u Truncating count from %zu to %llu\n", __func__,
195 			__LINE__, count, size - *pos);
196 		count = size - *pos;
197 	}
198 
199 	sector = *pos / dev->bounce_size * priv->chunk_sectors;
200 	offset = *pos % dev->bounce_size;
201 
202 	remaining = count;
203 	do {
204 		n = min_t(u64, remaining, dev->bounce_size - offset);
205 		dst = dev->bounce_buf + offset;
206 
207 		mutex_lock(&priv->mutex);
208 
209 		if (n != dev->bounce_size)
210 			res = ps3flash_fetch(dev, sector);
211 		else if (sector != priv->tag)
212 			res = ps3flash_writeback(dev);
213 		if (res)
214 			goto fail;
215 
216 		dev_dbg(&dev->sbd.core,
217 			"%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
218 			__func__, __LINE__, n, userbuf, kernelbuf, dst);
219 		if (userbuf) {
220 			if (copy_from_user(dst, userbuf, n)) {
221 				res = -EFAULT;
222 				goto fail;
223 			}
224 			userbuf += n;
225 		}
226 		if (kernelbuf) {
227 			memcpy(dst, kernelbuf, n);
228 			kernelbuf += n;
229 		}
230 
231 		priv->tag = sector;
232 		priv->dirty = true;
233 
234 		mutex_unlock(&priv->mutex);
235 
236 		*pos += n;
237 		remaining -= n;
238 		sector += priv->chunk_sectors;
239 		offset = 0;
240 	} while (remaining > 0);
241 
242 	return count;
243 
244 fail:
245 	mutex_unlock(&priv->mutex);
246 	return res;
247 }
248 
249 static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
250 				  size_t count, loff_t *pos)
251 {
252 	return ps3flash_read(buf, NULL, count, pos);
253 }
254 
255 static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
256 				   size_t count, loff_t *pos)
257 {
258 	return ps3flash_write(buf, NULL, count, pos);
259 }
260 
261 static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
262 {
263 	return ps3flash_read(NULL, buf, count, &pos);
264 }
265 
266 static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
267 				     loff_t pos)
268 {
269 	ssize_t res;
270 	int wb;
271 
272 	res = ps3flash_write(NULL, buf, count, &pos);
273 	if (res < 0)
274 		return res;
275 
276 	/* Make kernel writes synchronous */
277 	wb = ps3flash_writeback(ps3flash_dev);
278 	if (wb)
279 		return wb;
280 
281 	return res;
282 }
283 
284 static int ps3flash_flush(struct file *file, fl_owner_t id)
285 {
286 	return ps3flash_writeback(ps3flash_dev);
287 }
288 
289 static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync)
290 {
291 	struct inode *inode = file_inode(file);
292 	int err;
293 	mutex_lock(&inode->i_mutex);
294 	err = ps3flash_writeback(ps3flash_dev);
295 	mutex_unlock(&inode->i_mutex);
296 	return err;
297 }
298 
299 static irqreturn_t ps3flash_interrupt(int irq, void *data)
300 {
301 	struct ps3_storage_device *dev = data;
302 	int res;
303 	u64 tag, status;
304 
305 	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
306 
307 	if (tag != dev->tag)
308 		dev_err(&dev->sbd.core,
309 			"%s:%u: tag mismatch, got %llx, expected %llx\n",
310 			__func__, __LINE__, tag, dev->tag);
311 
312 	if (res) {
313 		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
314 			__func__, __LINE__, res, status);
315 	} else {
316 		dev->lv1_status = status;
317 		complete(&dev->done);
318 	}
319 	return IRQ_HANDLED;
320 }
321 
322 static const struct file_operations ps3flash_fops = {
323 	.owner	= THIS_MODULE,
324 	.llseek	= ps3flash_llseek,
325 	.read	= ps3flash_user_read,
326 	.write	= ps3flash_user_write,
327 	.flush	= ps3flash_flush,
328 	.fsync	= ps3flash_fsync,
329 };
330 
331 static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
332 	.read	= ps3flash_kernel_read,
333 	.write	= ps3flash_kernel_write,
334 };
335 
336 static struct miscdevice ps3flash_misc = {
337 	.minor	= MISC_DYNAMIC_MINOR,
338 	.name	= DEVICE_NAME,
339 	.fops	= &ps3flash_fops,
340 };
341 
342 static int ps3flash_probe(struct ps3_system_bus_device *_dev)
343 {
344 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
345 	struct ps3flash_private *priv;
346 	int error;
347 	unsigned long tmp;
348 
349 	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
350 	if (tmp % FLASH_BLOCK_SIZE) {
351 		dev_err(&dev->sbd.core,
352 			"%s:%u region start %lu is not aligned\n", __func__,
353 			__LINE__, tmp);
354 		return -EINVAL;
355 	}
356 	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
357 	if (tmp % FLASH_BLOCK_SIZE) {
358 		dev_err(&dev->sbd.core,
359 			"%s:%u region size %lu is not aligned\n", __func__,
360 			__LINE__, tmp);
361 		return -EINVAL;
362 	}
363 
364 	/* use static buffer, kmalloc cannot allocate 256 KiB */
365 	if (!ps3flash_bounce_buffer.address)
366 		return -ENODEV;
367 
368 	if (ps3flash_dev) {
369 		dev_err(&dev->sbd.core,
370 			"Only one FLASH device is supported\n");
371 		return -EBUSY;
372 	}
373 
374 	ps3flash_dev = dev;
375 
376 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
377 	if (!priv) {
378 		error = -ENOMEM;
379 		goto fail;
380 	}
381 
382 	ps3_system_bus_set_drvdata(&dev->sbd, priv);
383 	mutex_init(&priv->mutex);
384 	priv->tag = -1;
385 
386 	dev->bounce_size = ps3flash_bounce_buffer.size;
387 	dev->bounce_buf = ps3flash_bounce_buffer.address;
388 	priv->chunk_sectors = dev->bounce_size / dev->blk_size;
389 
390 	error = ps3stor_setup(dev, ps3flash_interrupt);
391 	if (error)
392 		goto fail_free_priv;
393 
394 	ps3flash_misc.parent = &dev->sbd.core;
395 	error = misc_register(&ps3flash_misc);
396 	if (error) {
397 		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
398 			__func__, __LINE__, error);
399 		goto fail_teardown;
400 	}
401 
402 	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
403 		 __func__, __LINE__, ps3flash_misc.minor);
404 
405 	ps3_os_area_flash_register(&ps3flash_kernel_ops);
406 	return 0;
407 
408 fail_teardown:
409 	ps3stor_teardown(dev);
410 fail_free_priv:
411 	kfree(priv);
412 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
413 fail:
414 	ps3flash_dev = NULL;
415 	return error;
416 }
417 
418 static int ps3flash_remove(struct ps3_system_bus_device *_dev)
419 {
420 	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
421 
422 	ps3_os_area_flash_register(NULL);
423 	misc_deregister(&ps3flash_misc);
424 	ps3stor_teardown(dev);
425 	kfree(ps3_system_bus_get_drvdata(&dev->sbd));
426 	ps3_system_bus_set_drvdata(&dev->sbd, NULL);
427 	ps3flash_dev = NULL;
428 	return 0;
429 }
430 
431 
432 static struct ps3_system_bus_driver ps3flash = {
433 	.match_id	= PS3_MATCH_ID_STOR_FLASH,
434 	.core.name	= DEVICE_NAME,
435 	.core.owner	= THIS_MODULE,
436 	.probe		= ps3flash_probe,
437 	.remove		= ps3flash_remove,
438 	.shutdown	= ps3flash_remove,
439 };
440 
441 
442 static int __init ps3flash_init(void)
443 {
444 	return ps3_system_bus_driver_register(&ps3flash);
445 }
446 
447 static void __exit ps3flash_exit(void)
448 {
449 	ps3_system_bus_driver_unregister(&ps3flash);
450 }
451 
452 module_init(ps3flash_init);
453 module_exit(ps3flash_exit);
454 
455 MODULE_LICENSE("GPL");
456 MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
457 MODULE_AUTHOR("Sony Corporation");
458 MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
459