drm/etnaviv: Implement mmap as GEM object function
[linux-2.6-microblaze.git] / drivers / char / ps3flash.c
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 void 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 }
417
418
419 static struct ps3_system_bus_driver ps3flash = {
420         .match_id       = PS3_MATCH_ID_STOR_FLASH,
421         .core.name      = DEVICE_NAME,
422         .core.owner     = THIS_MODULE,
423         .probe          = ps3flash_probe,
424         .remove         = ps3flash_remove,
425         .shutdown       = ps3flash_remove,
426 };
427
428
429 static int __init ps3flash_init(void)
430 {
431         return ps3_system_bus_driver_register(&ps3flash);
432 }
433
434 static void __exit ps3flash_exit(void)
435 {
436         ps3_system_bus_driver_unregister(&ps3flash);
437 }
438
439 module_init(ps3flash_init);
440 module_exit(ps3flash_exit);
441
442 MODULE_LICENSE("GPL");
443 MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
444 MODULE_AUTHOR("Sony Corporation");
445 MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);