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