root/drivers/char/ps3flash.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ps3flash_read_write_sectors
  2. ps3flash_writeback
  3. ps3flash_fetch
  4. ps3flash_llseek
  5. ps3flash_read
  6. ps3flash_write
  7. ps3flash_user_read
  8. ps3flash_user_write
  9. ps3flash_kernel_read
  10. ps3flash_kernel_write
  11. ps3flash_flush
  12. ps3flash_fsync
  13. ps3flash_interrupt
  14. ps3flash_probe
  15. ps3flash_remove
  16. ps3flash_init
  17. ps3flash_exit

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

/* [<][>][^][v][top][bottom][index][help] */