initial import
[ps3linux_kernel_patches_314.git] / 0030-ps3flash.patch
blob81eee59ca713fefb0054d24bbc8a377a8e37c5a3
1 --- a/arch/powerpc/include/asm/ps3.h 2012-01-24 18:09:05.452290538 +0100
2 +++ b/arch/powerpc/include/asm/ps3.h 2012-01-24 18:37:24.181894425 +0100
3 @@ -326,6 +326,7 @@
4 PS3_MATCH_ID_SOUND = 9,
5 PS3_MATCH_ID_GPU = 10,
6 PS3_MATCH_ID_LPM = 11,
7 + PS3_MATCH_ID_STOR_NOR_FLASH = 12,
8 };
10 enum ps3_match_sub_id {
11 @@ -345,6 +346,7 @@
12 #define PS3_MODULE_ALIAS_GPU_FB "ps3:10:1"
13 #define PS3_MODULE_ALIAS_GPU_RAMDISK "ps3:10:2"
14 #define PS3_MODULE_ALIAS_LPM "ps3:11:0"
15 +#define PS3_MODULE_ALIAS_STOR_NOR_FLASH "ps3:12:0"
17 enum ps3_system_bus_device_type {
18 PS3_DEVICE_TYPE_IOC0 = 1,
19 --- a/arch/powerpc/platforms/ps3/platform.h 2012-01-12 20:42:45.000000000 +0100
20 +++ b/arch/powerpc/platforms/ps3/platform.h 2012-01-24 18:36:02.470631575 +0100
21 @@ -88,6 +88,7 @@
22 PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */
23 PS3_DEV_TYPE_SB_GPIO = 6,
24 PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
25 + PS3_DEV_TYPE_STOR_NOR_FLASH = 254,
28 int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
29 --- a/arch/powerpc/platforms/ps3/device-init.c 2012-01-12 20:42:45.000000000 +0100
30 +++ b/arch/powerpc/platforms/ps3/device-init.c 2012-01-24 18:34:44.089470755 +0100
31 @@ -592,6 +592,13 @@
32 __func__, __LINE__);
33 break;
35 + case PS3_DEV_TYPE_STOR_NOR_FLASH:
36 + result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_NOR_FLASH);
37 + if (result)
38 + pr_debug("%s:%u ps3_setup_storage_dev failed\n",
39 + __func__, __LINE__);
40 + break;
42 default:
43 result = 0;
44 pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__,
45 --- a/arch/powerpc/platforms/ps3/system-bus.c 2012-01-12 20:42:45.000000000 +0100
46 +++ b/arch/powerpc/platforms/ps3/system-bus.c 2012-01-24 19:25:53.073547395 +0100
47 @@ -174,6 +174,7 @@
48 case PS3_MATCH_ID_STOR_DISK:
49 case PS3_MATCH_ID_STOR_ROM:
50 case PS3_MATCH_ID_STOR_FLASH:
51 + case PS3_MATCH_ID_STOR_NOR_FLASH:
52 return ps3_open_hv_device_sb(dev);
54 case PS3_MATCH_ID_SOUND:
55 @@ -212,6 +213,7 @@
56 case PS3_MATCH_ID_STOR_DISK:
57 case PS3_MATCH_ID_STOR_ROM:
58 case PS3_MATCH_ID_STOR_FLASH:
59 + case PS3_MATCH_ID_STOR_NOR_FLASH:
60 return ps3_close_hv_device_sb(dev);
62 case PS3_MATCH_ID_SOUND:
63 --- a/arch/powerpc/platforms/ps3/Kconfig 2012-01-24 19:02:19.221491270 +0100
64 +++ b/arch/powerpc/platforms/ps3/Kconfig 2012-01-24 19:03:21.419302797 +0100
65 @@ -128,6 +128,26 @@
66 be disabled on the kernel command line using "ps3flash=off", to
67 not allocate this fixed buffer.
69 +config PS3_FLASH_NG
70 + tristate "PS3 Flash Storage Driver"
71 + depends on PPC_PS3 && BLOCK && PS3_FLASH!=y && PS3_FLASH!=m
72 + select PS3_STORAGE
73 + help
74 + Include support for the PS3 Flash Storage.
76 + This support is required to access the PS3 flash.
77 + In general, all users will say Y or M.
79 +config PS3_NOR_FLASH
80 + tristate "PS3 NOR Flash Storage Driver"
81 + depends on PPC_PS3 && BLOCK
82 + select PS3_STORAGE
83 + help
84 + Include support for the PS3 NOR Flash Storage.
86 + This support is required to access the PS3 NOR flash.
87 + In general, all users will say Y or M.
89 config PS3_VRAM
90 tristate "PS3 Video RAM Storage Driver"
91 depends on FB_PS3=y && BLOCK && m
92 --- a/drivers/block/Makefile 2012-01-24 19:02:39.908639282 +0100
93 +++ b/drivers/block/Makefile 2012-01-24 18:32:56.294515362 +0100
94 @@ -10,6 +10,8 @@
95 obj-$(CONFIG_BLK_DEV_FD) += floppy.o
96 obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
97 obj-$(CONFIG_PS3_DISK) += ps3disk.o
98 +obj-$(CONFIG_PS3_FLASH_NG) += ps3flash.o
99 +obj-$(CONFIG_PS3_NOR_FLASH) += ps3nflash.o
100 obj-$(CONFIG_PS3_VRAM) += ps3vram.o
101 obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
102 obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
103 --- /dev/null 2012-11-28 15:48:49.557690341 +0100
104 +++ b/drivers/block/ps3flash.c 2013-02-14 11:18:29.076533279 +0100
105 @@ -0,0 +1,520 @@
107 + * PS3 Flash Storage Driver
109 + * Copyright (C) 2007 Sony Computer Entertainment Inc.
110 + * Copyright 2007 Sony Corp.
111 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>.
112 + * Copyright (C) 2011-2013 glevand <geoffrey.levand@mail.ru>.
114 + * This program is free software; you can redistribute it and/or modify it
115 + * under the terms of the GNU General Public License as published
116 + * by the Free Software Foundation; version 2 of the License.
118 + * This program is distributed in the hope that it will be useful, but
119 + * WITHOUT ANY WARRANTY; without even the implied warranty of
120 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
121 + * General Public License for more details.
123 + * You should have received a copy of the GNU General Public License along
124 + * with this program; if not, write to the Free Software Foundation, Inc.,
125 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
126 + */
128 +#include <linux/blkdev.h>
129 +#include <linux/slab.h>
130 +#include <linux/module.h>
132 +#include <asm/lv1call.h>
133 +#include <asm/ps3stor.h>
134 +#include <asm/firmware.h>
137 +#define DEVICE_NAME "ps3flash"
139 +#define BOUNCE_SIZE (64*1024)
141 +#define PS3FLASH_MAX_NUM_REGS 8
143 +#define PS3FLASH_MINORS 16
146 +#define PS3FLASH_NAME "ps3flash%c"
149 +struct ps3flash_private {
150 + spinlock_t lock; /* Request queue spinlock */
151 + unsigned int blocking_factor;
152 + struct request *req;
153 + u64 raw_capacity;
154 + int is_vflash;
155 + struct gendisk *gendisk[PS3FLASH_MAX_NUM_REGS];
156 + struct request_queue *queue[PS3FLASH_MAX_NUM_REGS];
157 + int next_queue;
161 +#define LV1_STORAGE_ATA_FLUSH_CACHE_EXT (0x31)
164 +static int ps3flash_major;
167 +static const struct block_device_operations ps3flash_fops = {
168 + .owner = THIS_MODULE,
171 +static unsigned int region_flags[] =
173 + 0x6, 0x2, 0x4, 0x4, 0x4, 0x0, 0x2, 0x0,
175 +module_param_array(region_flags, uint, NULL, S_IRUGO);
176 +MODULE_PARM_DESC(region_flags, "Region flags");
179 +static void ps3flash_scatter_gather(struct ps3_storage_device *dev,
180 + struct request *req, int gather)
182 + unsigned int offset = 0;
183 + struct req_iterator iter;
184 + struct bio_vec *bvec;
185 + unsigned int i = 0;
186 + size_t size;
187 + void *buf;
189 + rq_for_each_segment(bvec, req, iter) {
190 + unsigned long flags;
191 + dev_dbg(&dev->sbd.core,
192 + "%s:%u: bio %u: %u segs %u sectors from %lu\n",
193 + __func__, __LINE__, i, bio_segments(iter.bio),
194 + bio_sectors(iter.bio), iter.bio->bi_sector);
196 + size = bvec->bv_len;
197 + buf = bvec_kmap_irq(bvec, &flags);
198 + if (gather)
199 + memcpy(dev->bounce_buf+offset, buf, size);
200 + else
201 + memcpy(buf, dev->bounce_buf+offset, size);
202 + offset += size;
203 + flush_kernel_dcache_page(bvec->bv_page);
204 + bvec_kunmap_irq(buf, &flags);
205 + i++;
209 +static int ps3flash_submit_request_sg(struct ps3_storage_device *dev,
210 + struct request *req)
212 + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
213 + int write = rq_data_dir(req), res;
214 + const char *op = write ? "write" : "read";
215 + u64 start_sector, sectors;
216 + unsigned int region_idx = MINOR(disk_devt(req->rq_disk)) / PS3FLASH_MINORS;
217 + unsigned int region_id = dev->regions[region_idx].id;
218 + unsigned int region_flags = dev->regions[region_idx].flags;
220 +#ifdef DEBUG
221 + unsigned int n = 0;
222 + struct bio_vec *bv;
223 + struct req_iterator iter;
225 + rq_for_each_segment(bv, req, iter)
226 + n++;
227 + dev_dbg(&dev->sbd.core,
228 + "%s:%u: %s req has %u bvecs for %u sectors\n",
229 + __func__, __LINE__, op, n, blk_rq_sectors(req));
230 +#endif
232 + start_sector = blk_rq_pos(req) * priv->blocking_factor;
233 + sectors = blk_rq_sectors(req) * priv->blocking_factor;
234 + dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
235 + __func__, __LINE__, op, sectors, start_sector);
237 + if (write) {
238 + ps3flash_scatter_gather(dev, req, 1);
240 + res = lv1_storage_write(dev->sbd.dev_id, region_id,
241 + start_sector, sectors, region_flags,
242 + dev->bounce_lpar, &dev->tag);
243 + } else {
244 + res = lv1_storage_read(dev->sbd.dev_id, region_id,
245 + start_sector, sectors, region_flags,
246 + dev->bounce_lpar, &dev->tag);
248 + if (res) {
249 + dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
250 + __LINE__, op, res);
251 + __blk_end_request_all(req, -EIO);
252 + return 0;
255 + priv->req = req;
256 + return 1;
259 +static int ps3flash_submit_flush_request(struct ps3_storage_device *dev,
260 + struct request *req)
262 + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
263 + u64 res;
265 + dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
267 + res = lv1_storage_send_device_command(dev->sbd.dev_id,
268 + LV1_STORAGE_ATA_FLUSH_CACHE_EXT, 0, 0, 0,
269 + 0, &dev->tag);
270 + if (res) {
271 + dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
272 + __func__, __LINE__, res);
273 + __blk_end_request_all(req, -EIO);
274 + return 0;
277 + priv->req = req;
278 + return 1;
281 +static void ps3flash_do_request(struct ps3_storage_device *dev,
282 + struct request_queue *q)
284 + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
285 + struct request *req;
287 + dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
289 + while ((req = blk_fetch_request(q))) {
290 + if (priv->is_vflash && (req->cmd_flags & REQ_FLUSH)) {
291 + if (ps3flash_submit_flush_request(dev, req))
292 + break;
293 + } else if (req->cmd_type == REQ_TYPE_FS) {
294 + if (ps3flash_submit_request_sg(dev, req))
295 + break;
296 + } else {
297 + blk_dump_rq_flags(req, DEVICE_NAME " bad request");
298 + __blk_end_request_all(req, -EIO);
299 + continue;
304 +static void ps3flash_request(struct request_queue *q)
306 + struct ps3_storage_device *dev = q->queuedata;
307 + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
309 + if (priv->req) {
310 + dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
311 + return;
314 + ps3flash_do_request(dev, q);
317 +static irqreturn_t ps3flash_interrupt(int irq, void *data)
319 + struct ps3_storage_device *dev = data;
320 + struct ps3flash_private *priv;
321 + struct request *req;
322 + int res, read, error;
323 + u64 tag, status;
324 + const char *op;
325 + struct request_queue *q;
326 + int old_queue;
328 + res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
330 + if (tag != dev->tag)
331 + dev_err(&dev->sbd.core,
332 + "%s:%u: tag mismatch, got %llx, expected %llx\n",
333 + __func__, __LINE__, tag, dev->tag);
335 + if (res) {
336 + dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
337 + __func__, __LINE__, res, status);
338 + return IRQ_HANDLED;
341 + priv = ps3_system_bus_get_drvdata(&dev->sbd);
342 + req = priv->req;
343 + if (!req) {
344 + dev_dbg(&dev->sbd.core,
345 + "%s:%u non-block layer request completed\n", __func__,
346 + __LINE__);
347 + dev->lv1_status = status;
348 + complete(&dev->done);
349 + return IRQ_HANDLED;
352 + if (req->cmd_flags & REQ_FLUSH) {
353 + read = 0;
354 + op = "flush";
355 + } else {
356 + read = !rq_data_dir(req);
357 + op = read ? "read" : "write";
359 + if (status) {
360 + dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
361 + __LINE__, op, status);
362 + error = -EIO;
363 + } else {
364 + dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
365 + __LINE__, op);
366 + error = 0;
367 + if (read)
368 + ps3flash_scatter_gather(dev, req, 0);
371 + spin_lock(&priv->lock);
372 + __blk_end_request_all(req, error);
373 + priv->req = NULL;
374 + old_queue = priv->next_queue;
375 + do {
376 + q = priv->queue[priv->next_queue];
378 + priv->next_queue++;
379 + if (priv->next_queue >= dev->num_regions)
380 + priv->next_queue = 0;
382 + if (q) {
383 + ps3flash_do_request(dev, q);
384 + if (priv->req)
385 + break;
387 + } while (old_queue != priv->next_queue);
388 + spin_unlock(&priv->lock);
390 + return IRQ_HANDLED;
393 +static int ps3flash_sync_cache(struct ps3_storage_device *dev)
395 + u64 res;
397 + dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
399 + res = ps3stor_send_command(dev, LV1_STORAGE_ATA_FLUSH_CACHE_EXT, 0, 0, 0, 0);
400 + if (res) {
401 + dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
402 + __func__, __LINE__, res);
403 + return -EIO;
405 + return 0;
408 +static int ps3flash_probe(struct ps3_system_bus_device *_dev)
410 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
411 + struct ps3flash_private *priv;
412 + int error;
413 + unsigned int regidx, devidx;
414 + u64 lpar_id, flash_ext_flag, junk;
415 + struct request_queue *queue;
416 + struct gendisk *gendisk;
418 + BUG_ON(dev->num_regions > PS3FLASH_MAX_NUM_REGS);
420 + if (dev->blk_size < 512) {
421 + dev_err(&dev->sbd.core,
422 + "%s:%u: cannot handle block size %llu\n", __func__,
423 + __LINE__, dev->blk_size);
424 + return -EINVAL;
427 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
428 + if (!priv) {
429 + error = -ENOMEM;
430 + goto fail;
433 + ps3_system_bus_set_drvdata(_dev, priv);
434 + spin_lock_init(&priv->lock);
436 + dev->bounce_size = BOUNCE_SIZE;
437 + dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
438 + if (!dev->bounce_buf) {
439 + error = -ENOMEM;
440 + goto fail_free_priv;
443 + for (regidx = 0; regidx < dev->num_regions; regidx++)
444 + dev->regions[regidx].flags = region_flags[regidx];
446 + error = ps3stor_setup(dev, ps3flash_interrupt);
447 + if (error)
448 + goto fail_free_bounce;
450 + priv->raw_capacity = dev->regions[0].size;
452 + error = lv1_get_logical_partition_id(&lpar_id);
453 + if (error)
454 + goto fail_teardown;
456 + error = lv1_read_repository_node(1, 0x0000000073797300ul /* sys */,
457 + 0x666c617368000000ul /* flash */,
458 + 0x6578740000000000ul /* ext */,
459 + 0, &flash_ext_flag, &junk);
460 + if (error)
461 + goto fail_teardown;
463 + priv->is_vflash = !(flash_ext_flag & 0x1);
465 + dev_info(&dev->sbd.core, "VFLASH is %s\n",
466 + priv->is_vflash ? "on" : "off");
468 + for (devidx = 0; devidx < dev->num_regions; devidx++)
470 + if (test_bit(devidx, &dev->accessible_regions) == 0)
471 + continue;
473 + queue = blk_init_queue(ps3flash_request, &priv->lock);
474 + if (!queue) {
475 + dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
476 + __func__, __LINE__);
477 + error = -ENOMEM;
478 + goto fail_cleanup;
481 + priv->queue[devidx] = queue;
482 + queue->queuedata = dev;
484 + blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
486 + blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
487 + blk_queue_segment_boundary(queue, -1UL);
488 + blk_queue_dma_alignment(queue, dev->blk_size-1);
489 + blk_queue_logical_block_size(queue, dev->blk_size);
491 + blk_queue_flush(queue, REQ_FLUSH);
493 + blk_queue_max_segments(queue, -1);
494 + blk_queue_max_segment_size(queue, dev->bounce_size);
496 + gendisk = alloc_disk(PS3FLASH_MINORS);
497 + if (!gendisk) {
498 + dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
499 + __LINE__);
500 + error = -ENOMEM;
501 + goto fail_cleanup;
504 + priv->gendisk[devidx] = gendisk;
505 + gendisk->major = ps3flash_major;
506 + gendisk->first_minor = devidx * PS3FLASH_MINORS;
507 + gendisk->fops = &ps3flash_fops;
508 + gendisk->queue = queue;
509 + gendisk->private_data = dev;
510 + gendisk->driverfs_dev = &dev->sbd.core;
511 + snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3FLASH_NAME,
512 + devidx+'a');
513 + priv->blocking_factor = dev->blk_size >> 9;
514 + set_capacity(gendisk,
515 + dev->regions[devidx].size*priv->blocking_factor);
517 + dev_info(&dev->sbd.core,
518 + "%s (%llu MiB total, %lu MiB region)\n",
519 + gendisk->disk_name, priv->raw_capacity >> 11,
520 + get_capacity(gendisk) >> 11);
522 + add_disk(gendisk);
525 + return 0;
527 +fail_cleanup:
528 + for (devidx = 0; devidx < dev->num_regions; devidx++)
530 + if (priv->gendisk[devidx]) {
531 + del_gendisk(priv->gendisk[devidx]);
532 + put_disk(priv->gendisk[devidx]);
535 + if (priv->queue[devidx])
536 + blk_cleanup_queue(priv->queue[devidx]);
538 +fail_teardown:
539 + ps3stor_teardown(dev);
540 +fail_free_bounce:
541 + kfree(dev->bounce_buf);
542 +fail_free_priv:
543 + kfree(priv);
544 + ps3_system_bus_set_drvdata(_dev, NULL);
545 +fail:
546 + return error;
549 +static int ps3flash_remove(struct ps3_system_bus_device *_dev)
551 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
552 + struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
553 + unsigned int devidx;
555 + for (devidx = 0; devidx < dev->num_regions; devidx++)
557 + if (priv->gendisk[devidx]) {
558 + del_gendisk(priv->gendisk[devidx]);
559 + put_disk(priv->gendisk[devidx]);
562 + if (priv->queue[devidx])
563 + blk_cleanup_queue(priv->queue[devidx]);
566 + if (priv->is_vflash) {
567 + dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
568 + ps3flash_sync_cache(dev);
571 + ps3stor_teardown(dev);
572 + kfree(dev->bounce_buf);
573 + kfree(priv);
574 + ps3_system_bus_set_drvdata(_dev, NULL);
575 + return 0;
578 +static struct ps3_system_bus_driver ps3flash = {
579 + .match_id = PS3_MATCH_ID_STOR_FLASH,
580 + .core.name = DEVICE_NAME,
581 + .core.owner = THIS_MODULE,
582 + .probe = ps3flash_probe,
583 + .remove = ps3flash_remove,
584 + .shutdown = ps3flash_remove,
588 +static int __init ps3flash_init(void)
590 + int error;
592 + if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
593 + return -ENODEV;
595 + error = register_blkdev(0, DEVICE_NAME);
596 + if (error <= 0) {
597 + printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
598 + __LINE__, error);
599 + return error;
601 + ps3flash_major = error;
603 + pr_info("%s:%u: registered block device major %d\n", __func__,
604 + __LINE__, ps3flash_major);
606 + error = ps3_system_bus_driver_register(&ps3flash);
607 + if (error)
608 + unregister_blkdev(ps3flash_major, DEVICE_NAME);
610 + return error;
613 +static void __exit ps3flash_exit(void)
615 + ps3_system_bus_driver_unregister(&ps3flash);
616 + unregister_blkdev(ps3flash_major, DEVICE_NAME);
619 +module_init(ps3flash_init);
620 +module_exit(ps3flash_exit);
622 +MODULE_LICENSE("GPL");
623 +MODULE_DESCRIPTION("PS3 Flash Storage Driver");
624 +MODULE_AUTHOR("Sony Corporation");
625 +MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
626 --- /dev/null 2013-02-15 18:37:48.373100583 +0100
627 +++ b/drivers/block/ps3nflash.c 2013-02-15 23:15:44.710737431 +0100
628 @@ -0,0 +1,448 @@
630 + * PS3 Flash Storage Driver
632 + * Copyright (C) 2007 Sony Computer Entertainment Inc.
633 + * Copyright 2007 Sony Corp.
634 + * Copyright (C) 2011 graf_chokolo <grafchokolo@gmail.com>.
635 + * Copyright (C) 2011-2013 glevand <geoffrey.levand@mail.ru>.
637 + * This program is free software; you can redistribute it and/or modify it
638 + * under the terms of the GNU General Public License as published
639 + * by the Free Software Foundation; version 2 of the License.
641 + * This program is distributed in the hope that it will be useful, but
642 + * WITHOUT ANY WARRANTY; without even the implied warranty of
643 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
644 + * General Public License for more details.
646 + * You should have received a copy of the GNU General Public License along
647 + * with this program; if not, write to the Free Software Foundation, Inc.,
648 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
649 + */
651 +#include <linux/blkdev.h>
652 +#include <linux/slab.h>
653 +#include <linux/module.h>
655 +#include <asm/lv1call.h>
656 +#include <asm/ps3stor.h>
657 +#include <asm/firmware.h>
660 +#define DEVICE_NAME "ps3nflash"
662 +#define BOUNCE_SIZE (64*1024)
664 +#define PS3NFLASH_MAX_NUM_REGS 8
666 +#define PS3NFLASH_MINORS 16
669 +#define PS3NFLASH_NAME "ps3nflash%c"
672 +struct ps3nflash_private {
673 + spinlock_t lock; /* Request queue spinlock */
674 + unsigned int blocking_factor;
675 + struct request *req;
676 + u64 raw_capacity;
677 + struct gendisk *gendisk[PS3NFLASH_MAX_NUM_REGS];
678 + struct request_queue *queue[PS3NFLASH_MAX_NUM_REGS];
679 + int next_queue;
683 +static int ps3nflash_major;
686 +static const struct block_device_operations ps3nflash_fops = {
687 + .owner = THIS_MODULE,
690 +static unsigned int region_flags[] =
692 + 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0,
694 +module_param_array(region_flags, uint, NULL, S_IRUGO);
695 +MODULE_PARM_DESC(region_flags, "Region flags");
698 +static void ps3nflash_scatter_gather(struct ps3_storage_device *dev,
699 + struct request *req, int gather)
701 + unsigned int offset = 0;
702 + struct req_iterator iter;
703 + struct bio_vec *bvec;
704 + unsigned int i = 0;
705 + size_t size;
706 + void *buf;
708 + rq_for_each_segment(bvec, req, iter) {
709 + unsigned long flags;
710 + dev_dbg(&dev->sbd.core,
711 + "%s:%u: bio %u: %u segs %u sectors from %lu\n",
712 + __func__, __LINE__, i, bio_segments(iter.bio),
713 + bio_sectors(iter.bio), iter.bio->bi_sector);
715 + size = bvec->bv_len;
716 + buf = bvec_kmap_irq(bvec, &flags);
717 + if (gather)
718 + memcpy(dev->bounce_buf+offset, buf, size);
719 + else
720 + memcpy(buf, dev->bounce_buf+offset, size);
721 + offset += size;
722 + flush_kernel_dcache_page(bvec->bv_page);
723 + bvec_kunmap_irq(buf, &flags);
724 + i++;
728 +static int ps3nflash_submit_request_sg(struct ps3_storage_device *dev,
729 + struct request *req)
731 + struct ps3nflash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
732 + int write = rq_data_dir(req), res;
733 + const char *op = write ? "write" : "read";
734 + u64 start_sector, sectors;
735 + unsigned int region_idx = MINOR(disk_devt(req->rq_disk)) / PS3NFLASH_MINORS;
736 + unsigned int region_id = dev->regions[region_idx].id;
737 + unsigned int region_flags = dev->regions[region_idx].flags;
739 +#ifdef DEBUG
740 + unsigned int n = 0;
741 + struct bio_vec *bv;
742 + struct req_iterator iter;
744 + rq_for_each_segment(bv, req, iter)
745 + n++;
746 + dev_dbg(&dev->sbd.core,
747 + "%s:%u: %s req has %u bvecs for %u sectors\n",
748 + __func__, __LINE__, op, n, blk_rq_sectors(req));
749 +#endif
751 + start_sector = blk_rq_pos(req) * priv->blocking_factor;
752 + sectors = blk_rq_sectors(req) * priv->blocking_factor;
753 + dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
754 + __func__, __LINE__, op, sectors, start_sector);
756 + if (write) {
757 + ps3nflash_scatter_gather(dev, req, 1);
759 + res = lv1_storage_write(dev->sbd.dev_id, region_id,
760 + start_sector, sectors, region_flags,
761 + dev->bounce_lpar, &dev->tag);
762 + } else {
763 + res = lv1_storage_read(dev->sbd.dev_id, region_id,
764 + start_sector, sectors, region_flags,
765 + dev->bounce_lpar, &dev->tag);
767 + if (res) {
768 + dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
769 + __LINE__, op, res);
770 + __blk_end_request_all(req, -EIO);
771 + return 0;
774 + priv->req = req;
775 + return 1;
778 +static void ps3nflash_do_request(struct ps3_storage_device *dev,
779 + struct request_queue *q)
781 + struct request *req;
783 + dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
785 + while ((req = blk_fetch_request(q))) {
786 + if (req->cmd_type == REQ_TYPE_FS) {
787 + if (ps3nflash_submit_request_sg(dev, req))
788 + break;
789 + } else {
790 + blk_dump_rq_flags(req, DEVICE_NAME " bad request");
791 + __blk_end_request_all(req, -EIO);
792 + continue;
797 +static void ps3nflash_request(struct request_queue *q)
799 + struct ps3_storage_device *dev = q->queuedata;
800 + struct ps3nflash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
802 + if (priv->req) {
803 + dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
804 + return;
807 + ps3nflash_do_request(dev, q);
810 +static irqreturn_t ps3nflash_interrupt(int irq, void *data)
812 + struct ps3_storage_device *dev = data;
813 + struct ps3nflash_private *priv;
814 + struct request *req;
815 + int res, read, error;
816 + u64 tag, status;
817 + const char *op;
818 + struct request_queue *q;
819 + int old_queue;
821 + res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
823 + if (tag != dev->tag)
824 + dev_err(&dev->sbd.core,
825 + "%s:%u: tag mismatch, got %llx, expected %llx\n",
826 + __func__, __LINE__, tag, dev->tag);
828 + if (res) {
829 + dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
830 + __func__, __LINE__, res, status);
831 + return IRQ_HANDLED;
834 + priv = ps3_system_bus_get_drvdata(&dev->sbd);
835 + req = priv->req;
836 + if (!req) {
837 + dev_dbg(&dev->sbd.core,
838 + "%s:%u non-block layer request completed\n", __func__,
839 + __LINE__);
840 + dev->lv1_status = status;
841 + complete(&dev->done);
842 + return IRQ_HANDLED;
845 + read = !rq_data_dir(req);
846 + op = read ? "read" : "write";
848 + if (status) {
849 + dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
850 + __LINE__, op, status);
851 + error = -EIO;
852 + } else {
853 + dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
854 + __LINE__, op);
855 + error = 0;
856 + if (read)
857 + ps3nflash_scatter_gather(dev, req, 0);
860 + spin_lock(&priv->lock);
861 + __blk_end_request_all(req, error);
862 + priv->req = NULL;
863 + old_queue = priv->next_queue;
864 + do {
865 + q = priv->queue[priv->next_queue];
867 + priv->next_queue++;
868 + if (priv->next_queue >= dev->num_regions)
869 + priv->next_queue = 0;
871 + if (q) {
872 + ps3nflash_do_request(dev, q);
873 + if (priv->req)
874 + break;
876 + } while (old_queue != priv->next_queue);
877 + spin_unlock(&priv->lock);
879 + return IRQ_HANDLED;
882 +static int ps3nflash_probe(struct ps3_system_bus_device *_dev)
884 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
885 + struct ps3nflash_private *priv;
886 + int error;
887 + unsigned int regidx, devidx;
888 + struct request_queue *queue;
889 + struct gendisk *gendisk;
891 + BUG_ON(dev->num_regions > PS3NFLASH_MAX_NUM_REGS);
893 + if (dev->blk_size < 512) {
894 + dev_err(&dev->sbd.core,
895 + "%s:%u: cannot handle block size %llu\n", __func__,
896 + __LINE__, dev->blk_size);
897 + return -EINVAL;
900 + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
901 + if (!priv) {
902 + error = -ENOMEM;
903 + goto fail;
906 + ps3_system_bus_set_drvdata(_dev, priv);
907 + spin_lock_init(&priv->lock);
909 + dev->bounce_size = BOUNCE_SIZE;
910 + dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
911 + if (!dev->bounce_buf) {
912 + error = -ENOMEM;
913 + goto fail_free_priv;
916 + for (regidx = 0; regidx < dev->num_regions; regidx++)
917 + dev->regions[regidx].flags = region_flags[regidx];
919 + error = ps3stor_setup(dev, ps3nflash_interrupt);
920 + if (error)
921 + goto fail_free_bounce;
923 + priv->raw_capacity = dev->regions[0].size;
925 + for (devidx = 0; devidx < dev->num_regions; devidx++)
927 + if (test_bit(devidx, &dev->accessible_regions) == 0)
928 + continue;
930 + queue = blk_init_queue(ps3nflash_request, &priv->lock);
931 + if (!queue) {
932 + dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
933 + __func__, __LINE__);
934 + error = -ENOMEM;
935 + goto fail_cleanup;
938 + priv->queue[devidx] = queue;
939 + queue->queuedata = dev;
941 + blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
943 + blk_queue_max_hw_sectors(queue, dev->bounce_size >> 9);
944 + blk_queue_segment_boundary(queue, -1UL);
945 + blk_queue_dma_alignment(queue, dev->blk_size-1);
946 + blk_queue_logical_block_size(queue, dev->blk_size);
948 + blk_queue_flush(queue, REQ_FLUSH);
950 + blk_queue_max_segments(queue, -1);
951 + blk_queue_max_segment_size(queue, dev->bounce_size);
953 + gendisk = alloc_disk(PS3NFLASH_MINORS);
954 + if (!gendisk) {
955 + dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
956 + __LINE__);
957 + error = -ENOMEM;
958 + goto fail_cleanup;
961 + priv->gendisk[devidx] = gendisk;
962 + gendisk->major = ps3nflash_major;
963 + gendisk->first_minor = devidx * PS3NFLASH_MINORS;
964 + gendisk->fops = &ps3nflash_fops;
965 + gendisk->queue = queue;
966 + gendisk->private_data = dev;
967 + gendisk->driverfs_dev = &dev->sbd.core;
968 + snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3NFLASH_NAME,
969 + devidx+'a');
970 + priv->blocking_factor = dev->blk_size >> 9;
971 + set_capacity(gendisk,
972 + dev->regions[devidx].size*priv->blocking_factor);
974 + dev_info(&dev->sbd.core,
975 + "%s (%llu MiB total, %lu MiB region)\n",
976 + gendisk->disk_name, priv->raw_capacity >> 11,
977 + get_capacity(gendisk) >> 11);
979 + add_disk(gendisk);
982 + return 0;
984 +fail_cleanup:
985 + for (devidx = 0; devidx < dev->num_regions; devidx++)
987 + if (priv->gendisk[devidx]) {
988 + del_gendisk(priv->gendisk[devidx]);
989 + put_disk(priv->gendisk[devidx]);
992 + if (priv->queue[devidx])
993 + blk_cleanup_queue(priv->queue[devidx]);
995 + ps3stor_teardown(dev);
996 +fail_free_bounce:
997 + kfree(dev->bounce_buf);
998 +fail_free_priv:
999 + kfree(priv);
1000 + ps3_system_bus_set_drvdata(_dev, NULL);
1001 +fail:
1002 + return error;
1005 +static int ps3nflash_remove(struct ps3_system_bus_device *_dev)
1007 + struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
1008 + struct ps3nflash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
1009 + unsigned int devidx;
1011 + for (devidx = 0; devidx < dev->num_regions; devidx++)
1013 + if (priv->gendisk[devidx]) {
1014 + del_gendisk(priv->gendisk[devidx]);
1015 + put_disk(priv->gendisk[devidx]);
1018 + if (priv->queue[devidx])
1019 + blk_cleanup_queue(priv->queue[devidx]);
1022 + ps3stor_teardown(dev);
1023 + kfree(dev->bounce_buf);
1024 + kfree(priv);
1025 + ps3_system_bus_set_drvdata(_dev, NULL);
1026 + return 0;
1029 +static struct ps3_system_bus_driver ps3nflash = {
1030 + .match_id = PS3_MATCH_ID_STOR_NOR_FLASH,
1031 + .core.name = DEVICE_NAME,
1032 + .core.owner = THIS_MODULE,
1033 + .probe = ps3nflash_probe,
1034 + .remove = ps3nflash_remove,
1035 + .shutdown = ps3nflash_remove,
1039 +static int __init ps3nflash_init(void)
1041 + int error;
1043 + if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
1044 + return -ENODEV;
1046 + error = register_blkdev(0, DEVICE_NAME);
1047 + if (error <= 0) {
1048 + printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
1049 + __LINE__, error);
1050 + return error;
1052 + ps3nflash_major = error;
1054 + pr_info("%s:%u: registered block device major %d\n", __func__,
1055 + __LINE__, ps3nflash_major);
1057 + error = ps3_system_bus_driver_register(&ps3nflash);
1058 + if (error)
1059 + unregister_blkdev(ps3nflash_major, DEVICE_NAME);
1061 + return error;
1064 +static void __exit ps3nflash_exit(void)
1066 + ps3_system_bus_driver_unregister(&ps3nflash);
1067 + unregister_blkdev(ps3nflash_major, DEVICE_NAME);
1070 +module_init(ps3nflash_init);
1071 +module_exit(ps3nflash_exit);
1073 +MODULE_LICENSE("GPL");
1074 +MODULE_DESCRIPTION("PS3 NOR Flash Storage Driver");
1075 +MODULE_AUTHOR("Sony Corporation");
1076 +MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_NOR_FLASH);