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