Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/ps3flash.c
26278 views
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);
446
447