OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [ps3flash.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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%lx\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 %lu\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(struct file *file, char __user *buf, size_t count,
108
                             loff_t *pos)
109
{
110
        struct ps3_storage_device *dev = ps3flash_dev;
111
        struct ps3flash_private *priv = dev->sbd.core.driver_data;
112
        u64 size, start_sector, end_sector, offset;
113
        ssize_t sectors_read;
114
        size_t remaining, n;
115
 
116
        dev_dbg(&dev->sbd.core,
117
                "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
118
                __func__, __LINE__, count, *pos, buf);
119
 
120
        size = dev->regions[dev->region_idx].size*dev->blk_size;
121
        if (*pos >= size || !count)
122
                return 0;
123
 
124
        if (*pos + count > size) {
125
                dev_dbg(&dev->sbd.core,
126
                        "%s:%u Truncating count from %zu to %llu\n", __func__,
127
                        __LINE__, count, size - *pos);
128
                count = size - *pos;
129
        }
130
 
131
        start_sector = *pos / dev->blk_size;
132
        offset = *pos % dev->blk_size;
133
        end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
134
 
135
        remaining = count;
136
        do {
137
                mutex_lock(&priv->mutex);
138
 
139
                sectors_read = ps3flash_read_sectors(dev, start_sector,
140
                                                     end_sector-start_sector,
141
                                                     0);
142
                if (sectors_read < 0) {
143
                        mutex_unlock(&priv->mutex);
144
                        goto fail;
145
                }
146
 
147
                n = min(remaining, sectors_read*dev->blk_size-offset);
148
                dev_dbg(&dev->sbd.core,
149
                        "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
150
                        __func__, __LINE__, n, dev->bounce_buf+offset, buf);
151
                if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
152
                        mutex_unlock(&priv->mutex);
153
                        sectors_read = -EFAULT;
154
                        goto fail;
155
                }
156
 
157
                mutex_unlock(&priv->mutex);
158
 
159
                *pos += n;
160
                buf += n;
161
                remaining -= n;
162
                start_sector += sectors_read;
163
                offset = 0;
164
        } while (remaining > 0);
165
 
166
        return count;
167
 
168
fail:
169
        return sectors_read;
170
}
171
 
172
static ssize_t ps3flash_write(struct file *file, const char __user *buf,
173
                              size_t count, loff_t *pos)
174
{
175
        struct ps3_storage_device *dev = ps3flash_dev;
176
        struct ps3flash_private *priv = dev->sbd.core.driver_data;
177
        u64 size, chunk_sectors, start_write_sector, end_write_sector,
178
            end_read_sector, start_read_sector, head, tail, offset;
179
        ssize_t res;
180
        size_t remaining, n;
181
        unsigned int sec_off;
182
 
183
        dev_dbg(&dev->sbd.core,
184
                "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
185
                __func__, __LINE__, count, *pos, buf);
186
 
187
        size = dev->regions[dev->region_idx].size*dev->blk_size;
188
        if (*pos >= size || !count)
189
                return 0;
190
 
191
        if (*pos + count > size) {
192
                dev_dbg(&dev->sbd.core,
193
                        "%s:%u Truncating count from %zu to %llu\n", __func__,
194
                        __LINE__, count, size - *pos);
195
                count = size - *pos;
196
        }
197
 
198
        chunk_sectors = dev->bounce_size / dev->blk_size;
199
 
200
        start_write_sector = *pos / dev->bounce_size * chunk_sectors;
201
        offset = *pos % dev->bounce_size;
202
        end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
203
                           chunk_sectors;
204
 
205
        end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
206
        start_read_sector = (*pos + count) / dev->blk_size;
207
 
208
        /*
209
         * As we have to write in 256 KiB chunks, while we can read in blk_size
210
         * (usually 512 bytes) chunks, we perform the following steps:
211
         *   1. Read from start_write_sector to end_read_sector ("head")
212
         *   2. Read from start_read_sector to end_write_sector ("tail")
213
         *   3. Copy data to buffer
214
         *   4. Write from start_write_sector to end_write_sector
215
         * All of this is complicated by using only one 256 KiB bounce buffer.
216
         */
217
 
218
        head = end_read_sector - start_write_sector;
219
        tail = end_write_sector - start_read_sector;
220
 
221
        remaining = count;
222
        do {
223
                mutex_lock(&priv->mutex);
224
 
225
                if (end_read_sector >= start_read_sector) {
226
                        /* Merge head and tail */
227
                        dev_dbg(&dev->sbd.core,
228
                                "Merged head and tail: %lu sectors at %lu\n",
229
                                chunk_sectors, start_write_sector);
230
                        res = ps3flash_read_sectors(dev, start_write_sector,
231
                                                    chunk_sectors, 0);
232
                        if (res < 0)
233
                                goto fail;
234
                } else {
235
                        if (head) {
236
                                /* Read head */
237
                                dev_dbg(&dev->sbd.core,
238
                                        "head: %lu sectors at %lu\n", head,
239
                                        start_write_sector);
240
                                res = ps3flash_read_sectors(dev,
241
                                                            start_write_sector,
242
                                                            head, 0);
243
                                if (res < 0)
244
                                        goto fail;
245
                        }
246
                        if (start_read_sector <
247
                            start_write_sector+chunk_sectors) {
248
                                /* Read tail */
249
                                dev_dbg(&dev->sbd.core,
250
                                        "tail: %lu sectors at %lu\n", tail,
251
                                        start_read_sector);
252
                                sec_off = start_read_sector-start_write_sector;
253
                                res = ps3flash_read_sectors(dev,
254
                                                            start_read_sector,
255
                                                            tail, sec_off);
256
                                if (res < 0)
257
                                        goto fail;
258
                        }
259
                }
260
 
261
                n = min(remaining, dev->bounce_size-offset);
262
                dev_dbg(&dev->sbd.core,
263
                        "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
264
                        __func__, __LINE__, n, buf, dev->bounce_buf+offset);
265
                if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
266
                        res = -EFAULT;
267
                        goto fail;
268
                }
269
 
270
                res = ps3flash_write_chunk(dev, start_write_sector);
271
                if (res < 0)
272
                        goto fail;
273
 
274
                mutex_unlock(&priv->mutex);
275
 
276
                *pos += n;
277
                buf += n;
278
                remaining -= n;
279
                start_write_sector += chunk_sectors;
280
                head = 0;
281
                offset = 0;
282
        } while (remaining > 0);
283
 
284
        return count;
285
 
286
fail:
287
        mutex_unlock(&priv->mutex);
288
        return res;
289
}
290
 
291
 
292
static irqreturn_t ps3flash_interrupt(int irq, void *data)
293
{
294
        struct ps3_storage_device *dev = data;
295
        int res;
296
        u64 tag, status;
297
 
298
        res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
299
 
300
        if (tag != dev->tag)
301
                dev_err(&dev->sbd.core,
302
                        "%s:%u: tag mismatch, got %lx, expected %lx\n",
303
                        __func__, __LINE__, tag, dev->tag);
304
 
305
        if (res) {
306
                dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
307
                        __func__, __LINE__, res, status);
308
        } else {
309
                dev->lv1_status = status;
310
                complete(&dev->done);
311
        }
312
        return IRQ_HANDLED;
313
}
314
 
315
 
316
static const struct file_operations ps3flash_fops = {
317
        .owner  = THIS_MODULE,
318
        .llseek = ps3flash_llseek,
319
        .read   = ps3flash_read,
320
        .write  = ps3flash_write,
321
};
322
 
323
static struct miscdevice ps3flash_misc = {
324
        .minor  = MISC_DYNAMIC_MINOR,
325
        .name   = DEVICE_NAME,
326
        .fops   = &ps3flash_fops,
327
};
328
 
329
static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
330
{
331
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
332
        struct ps3flash_private *priv;
333
        int error;
334
        unsigned long tmp;
335
 
336
        tmp = dev->regions[dev->region_idx].start*dev->blk_size;
337
        if (tmp % FLASH_BLOCK_SIZE) {
338
                dev_err(&dev->sbd.core,
339
                        "%s:%u region start %lu is not aligned\n", __func__,
340
                        __LINE__, tmp);
341
                return -EINVAL;
342
        }
343
        tmp = dev->regions[dev->region_idx].size*dev->blk_size;
344
        if (tmp % FLASH_BLOCK_SIZE) {
345
                dev_err(&dev->sbd.core,
346
                        "%s:%u region size %lu is not aligned\n", __func__,
347
                        __LINE__, tmp);
348
                return -EINVAL;
349
        }
350
 
351
        /* use static buffer, kmalloc cannot allocate 256 KiB */
352
        if (!ps3flash_bounce_buffer.address)
353
                return -ENODEV;
354
 
355
        if (ps3flash_dev) {
356
                dev_err(&dev->sbd.core,
357
                        "Only one FLASH device is supported\n");
358
                return -EBUSY;
359
        }
360
 
361
        ps3flash_dev = dev;
362
 
363
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
364
        if (!priv) {
365
                error = -ENOMEM;
366
                goto fail;
367
        }
368
 
369
        dev->sbd.core.driver_data = priv;
370
        mutex_init(&priv->mutex);
371
 
372
        dev->bounce_size = ps3flash_bounce_buffer.size;
373
        dev->bounce_buf = ps3flash_bounce_buffer.address;
374
 
375
        error = ps3stor_setup(dev, ps3flash_interrupt);
376
        if (error)
377
                goto fail_free_priv;
378
 
379
        ps3flash_misc.parent = &dev->sbd.core;
380
        error = misc_register(&ps3flash_misc);
381
        if (error) {
382
                dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
383
                        __func__, __LINE__, error);
384
                goto fail_teardown;
385
        }
386
 
387
        dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
388
                 __func__, __LINE__, ps3flash_misc.minor);
389
        return 0;
390
 
391
fail_teardown:
392
        ps3stor_teardown(dev);
393
fail_free_priv:
394
        kfree(priv);
395
        dev->sbd.core.driver_data = NULL;
396
fail:
397
        ps3flash_dev = NULL;
398
        return error;
399
}
400
 
401
static int ps3flash_remove(struct ps3_system_bus_device *_dev)
402
{
403
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
404
 
405
        misc_deregister(&ps3flash_misc);
406
        ps3stor_teardown(dev);
407
        kfree(dev->sbd.core.driver_data);
408
        dev->sbd.core.driver_data = NULL;
409
        ps3flash_dev = NULL;
410
        return 0;
411
}
412
 
413
 
414
static struct ps3_system_bus_driver ps3flash = {
415
        .match_id       = PS3_MATCH_ID_STOR_FLASH,
416
        .core.name      = DEVICE_NAME,
417
        .core.owner     = THIS_MODULE,
418
        .probe          = ps3flash_probe,
419
        .remove         = ps3flash_remove,
420
        .shutdown       = ps3flash_remove,
421
};
422
 
423
 
424
static int __init ps3flash_init(void)
425
{
426
        return ps3_system_bus_driver_register(&ps3flash);
427
}
428
 
429
static void __exit ps3flash_exit(void)
430
{
431
        ps3_system_bus_driver_unregister(&ps3flash);
432
}
433
 
434
module_init(ps3flash_init);
435
module_exit(ps3flash_exit);
436
 
437
MODULE_LICENSE("GPL");
438
MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
439
MODULE_AUTHOR("Sony Corporation");
440
MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.