aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2009-06-10 00:39:06 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-06-15 02:47:26 -0400
commita4e623fbc9b201930abcf78df6db5e49aa8e00cb (patch)
tree60017689df8260806cba7c007f9f9d85e3758b31
parent47cb996b059e0e5696b8daa1f62881a6462a251a (diff)
ps3: Replace direct file operations by callback
Currently the FLASH database is updated by the kernel using file operations, meant for userspace only. While this works for us because copy_{from,to}_user() on powerpc can handle kernel pointers, this is unportable and a bad example. Replace the file operations by callbacks, registered by the ps3flash driver. Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/ps3.h7
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c138
-rw-r--r--drivers/char/ps3flash.c94
3 files changed, 152 insertions, 87 deletions
diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h
index 7660694ab3ca..7f065e178ec4 100644
--- a/arch/powerpc/include/asm/ps3.h
+++ b/arch/powerpc/include/asm/ps3.h
@@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
53extern u64 ps3_os_area_get_rtc_diff(void); 53extern u64 ps3_os_area_get_rtc_diff(void);
54extern void ps3_os_area_set_rtc_diff(u64 rtc_diff); 54extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
55 55
56struct ps3_os_area_flash_ops {
57 ssize_t (*read)(void *buf, size_t count, loff_t pos);
58 ssize_t (*write)(const void *buf, size_t count, loff_t pos);
59};
60
61extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
62
56/* dma routines */ 63/* dma routines */
57 64
58enum ps3_dma_page_size { 65enum ps3_dma_page_size {
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 6e4125d6150f..d6487a9c8019 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
226 .value = &saved_params.av_multi_out, 226 .value = &saved_params.av_multi_out,
227}; 227};
228 228
229
230static DEFINE_MUTEX(os_area_flash_mutex);
231
232static const struct ps3_os_area_flash_ops *os_area_flash_ops;
233
234void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
235{
236 mutex_lock(&os_area_flash_mutex);
237 os_area_flash_ops = ops;
238 mutex_unlock(&os_area_flash_mutex);
239}
240EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
241
242static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
243{
244 ssize_t res = -ENODEV;
245
246 mutex_lock(&os_area_flash_mutex);
247 if (os_area_flash_ops)
248 res = os_area_flash_ops->read(buf, count, pos);
249 mutex_unlock(&os_area_flash_mutex);
250
251 return res;
252}
253
254static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
255{
256 ssize_t res = -ENODEV;
257
258 mutex_lock(&os_area_flash_mutex);
259 if (os_area_flash_ops)
260 res = os_area_flash_ops->write(buf, count, pos);
261 mutex_unlock(&os_area_flash_mutex);
262
263 return res;
264}
265
266
229/** 267/**
230 * os_area_set_property - Add or overwrite a saved_params value to the device tree. 268 * os_area_set_property - Add or overwrite a saved_params value to the device tree.
231 * 269 *
@@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db)
352 if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM, 390 if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
353 sizeof(db->magic_num))) { 391 sizeof(db->magic_num))) {
354 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__); 392 pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
355 return -1; 393 return -EINVAL;
356 } 394 }
357 395
358 if (db->version != 1) { 396 if (db->version != 1) {
359 pr_debug("%s:%d version failed\n", __func__, __LINE__); 397 pr_debug("%s:%d version failed\n", __func__, __LINE__);
360 return -1; 398 return -EINVAL;
361 } 399 }
362 400
363 return 0; 401 return 0;
@@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db)
578 * 616 *
579 */ 617 */
580 618
581static void __maybe_unused update_flash_db(void) 619static int update_flash_db(void)
582{ 620{
583 int result; 621 const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
584 int file; 622 struct os_area_header *header;
585 off_t offset;
586 ssize_t count; 623 ssize_t count;
587 static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE; 624 int error;
588 const struct os_area_header *header; 625 loff_t pos;
589 struct os_area_db* db; 626 struct os_area_db* db;
590 627
591 /* Read in header and db from flash. */ 628 /* Read in header and db from flash. */
592 629
593 file = sys_open("/dev/ps3flash", O_RDWR, 0);
594
595 if (file < 0) {
596 pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
597 goto fail_open;
598 }
599
600 header = kmalloc(buf_len, GFP_KERNEL); 630 header = kmalloc(buf_len, GFP_KERNEL);
601
602 if (!header) { 631 if (!header) {
603 pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__); 632 pr_debug("%s: kmalloc failed\n", __func__);
604 goto fail_malloc; 633 return -ENOMEM;
605 } 634 }
606 635
607 offset = sys_lseek(file, 0, SEEK_SET); 636 count = os_area_flash_read(header, buf_len, 0);
608 637 if (count < 0) {
609 if (offset != 0) { 638 pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
610 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__); 639 count);
611 goto fail_header_seek; 640 error = count;
641 goto fail;
612 } 642 }
613 643
614 count = sys_read(file, (char __user *)header, buf_len); 644 pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
615 645 if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
616 result = count < OS_AREA_SEGMENT_SIZE || verify_header(header) 646 count < pos) {
617 || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE; 647 pr_debug("%s: verify_header failed\n", __func__);
618
619 if (result) {
620 pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
621 dump_header(header); 648 dump_header(header);
622 goto fail_header; 649 error = -EINVAL;
650 goto fail;
623 } 651 }
624 652
625 /* Now got a good db offset and some maybe good db data. */ 653 /* Now got a good db offset and some maybe good db data. */
626 654
627 db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE; 655 db = (void *)header + pos;
628 656
629 result = db_verify(db); 657 error = db_verify(db);
630 658 if (error) {
631 if (result) { 659 pr_notice("%s: Verify of flash database failed, formatting.\n",
632 printk(KERN_NOTICE "%s:%d: Verify of flash database failed, " 660 __func__);
633 "formatting.\n", __func__, __LINE__);
634 dump_db(db); 661 dump_db(db);
635 os_area_db_init(db); 662 os_area_db_init(db);
636 } 663 }
@@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void)
639 666
640 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff); 667 db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
641 668
642 offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE, 669 count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
643 SEEK_SET);
644
645 if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
646 pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
647 goto fail_db_seek;
648 }
649
650 count = sys_write(file, (const char __user *)db,
651 sizeof(struct os_area_db));
652
653 if (count < sizeof(struct os_area_db)) { 670 if (count < sizeof(struct os_area_db)) {
654 pr_debug("%s:%d sys_write failed\n", __func__, __LINE__); 671 pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
672 count);
673 error = count < 0 ? count : -EIO;
655 } 674 }
656 675
657fail_db_seek: 676fail:
658fail_header:
659fail_header_seek:
660 kfree(header); 677 kfree(header);
661fail_malloc: 678 return error;
662 sys_close(file);
663fail_open:
664 return;
665} 679}
666 680
667/** 681/**
@@ -674,11 +688,11 @@ fail_open:
674static void os_area_queue_work_handler(struct work_struct *work) 688static void os_area_queue_work_handler(struct work_struct *work)
675{ 689{
676 struct device_node *node; 690 struct device_node *node;
691 int error;
677 692
678 pr_debug(" -> %s:%d\n", __func__, __LINE__); 693 pr_debug(" -> %s:%d\n", __func__, __LINE__);
679 694
680 node = of_find_node_by_path("/"); 695 node = of_find_node_by_path("/");
681
682 if (node) { 696 if (node) {
683 os_area_set_property(node, &property_rtc_diff); 697 os_area_set_property(node, &property_rtc_diff);
684 of_node_put(node); 698 of_node_put(node);
@@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work)
686 pr_debug("%s:%d of_find_node_by_path failed\n", 700 pr_debug("%s:%d of_find_node_by_path failed\n",
687 __func__, __LINE__); 701 __func__, __LINE__);
688 702
689#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE) 703 error = update_flash_db();
690 update_flash_db(); 704 if (error)
691#else 705 pr_warning("%s: Could not update FLASH ROM\n", __func__);
692 printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n", 706
693 __func__, __LINE__);
694#endif
695 pr_debug(" <- %s:%d\n", __func__, __LINE__); 707 pr_debug(" <- %s:%d\n", __func__, __LINE__);
696} 708}
697 709
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
index 184e6ed2393d..f7f21f47ea02 100644
--- a/drivers/char/ps3flash.c
+++ b/drivers/char/ps3flash.c
@@ -104,18 +104,19 @@ out:
104 return res; 104 return res;
105} 105}
106 106
107static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, 107static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
108 loff_t *pos) 108 size_t count, loff_t *pos)
109{ 109{
110 struct ps3_storage_device *dev = ps3flash_dev; 110 struct ps3_storage_device *dev = ps3flash_dev;
111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); 111 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
112 u64 size, start_sector, end_sector, offset; 112 u64 size, start_sector, end_sector, offset;
113 ssize_t sectors_read; 113 ssize_t sectors_read;
114 size_t remaining, n; 114 size_t remaining, n;
115 const void *src;
115 116
116 dev_dbg(&dev->sbd.core, 117 dev_dbg(&dev->sbd.core,
117 "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", 118 "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
118 __func__, __LINE__, count, *pos, buf); 119 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
119 120
120 size = dev->regions[dev->region_idx].size*dev->blk_size; 121 size = dev->regions[dev->region_idx].size*dev->blk_size;
121 if (*pos >= size || !count) 122 if (*pos >= size || !count)
@@ -145,19 +146,26 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
145 } 146 }
146 147
147 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); 148 n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
149 src = dev->bounce_buf+offset;
148 dev_dbg(&dev->sbd.core, 150 dev_dbg(&dev->sbd.core,
149 "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", 151 "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
150 __func__, __LINE__, n, dev->bounce_buf+offset, buf); 152 __func__, __LINE__, n, src, userbuf, kernelbuf);
151 if (copy_to_user(buf, dev->bounce_buf+offset, n)) { 153 if (userbuf) {
152 mutex_unlock(&priv->mutex); 154 if (copy_to_user(userbuf, src, n)) {
153 sectors_read = -EFAULT; 155 mutex_unlock(&priv->mutex);
154 goto fail; 156 sectors_read = -EFAULT;
157 goto fail;
158 }
159 userbuf += n;
160 }
161 if (kernelbuf) {
162 memcpy(kernelbuf, src, n);
163 kernelbuf += n;
155 } 164 }
156 165
157 mutex_unlock(&priv->mutex); 166 mutex_unlock(&priv->mutex);
158 167
159 *pos += n; 168 *pos += n;
160 buf += n;
161 remaining -= n; 169 remaining -= n;
162 start_sector += sectors_read; 170 start_sector += sectors_read;
163 offset = 0; 171 offset = 0;
@@ -169,8 +177,8 @@ fail:
169 return sectors_read; 177 return sectors_read;
170} 178}
171 179
172static ssize_t ps3flash_write(struct file *file, const char __user *buf, 180static ssize_t ps3flash_write(const char __user *userbuf,
173 size_t count, loff_t *pos) 181 const void *kernelbuf, size_t count, loff_t *pos)
174{ 182{
175 struct ps3_storage_device *dev = ps3flash_dev; 183 struct ps3_storage_device *dev = ps3flash_dev;
176 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); 184 struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
@@ -179,10 +187,11 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
179 ssize_t res; 187 ssize_t res;
180 size_t remaining, n; 188 size_t remaining, n;
181 unsigned int sec_off; 189 unsigned int sec_off;
190 void *dst;
182 191
183 dev_dbg(&dev->sbd.core, 192 dev_dbg(&dev->sbd.core,
184 "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", 193 "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
185 __func__, __LINE__, count, *pos, buf); 194 __func__, __LINE__, count, *pos, userbuf, kernelbuf);
186 195
187 size = dev->regions[dev->region_idx].size*dev->blk_size; 196 size = dev->regions[dev->region_idx].size*dev->blk_size;
188 if (*pos >= size || !count) 197 if (*pos >= size || !count)
@@ -259,12 +268,20 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
259 } 268 }
260 269
261 n = min_t(u64, remaining, dev->bounce_size-offset); 270 n = min_t(u64, remaining, dev->bounce_size-offset);
271 dst = dev->bounce_buf+offset;
262 dev_dbg(&dev->sbd.core, 272 dev_dbg(&dev->sbd.core,
263 "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", 273 "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
264 __func__, __LINE__, n, buf, dev->bounce_buf+offset); 274 __func__, __LINE__, n, userbuf, kernelbuf, dst);
265 if (copy_from_user(dev->bounce_buf+offset, buf, n)) { 275 if (userbuf) {
266 res = -EFAULT; 276 if (copy_from_user(dst, userbuf, n)) {
267 goto fail; 277 res = -EFAULT;
278 goto fail;
279 }
280 userbuf += n;
281 }
282 if (kernelbuf) {
283 memcpy(dst, kernelbuf, n);
284 kernelbuf += n;
268 } 285 }
269 286
270 res = ps3flash_write_chunk(dev, start_write_sector); 287 res = ps3flash_write_chunk(dev, start_write_sector);
@@ -274,7 +291,6 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
274 mutex_unlock(&priv->mutex); 291 mutex_unlock(&priv->mutex);
275 292
276 *pos += n; 293 *pos += n;
277 buf += n;
278 remaining -= n; 294 remaining -= n;
279 start_write_sector += chunk_sectors; 295 start_write_sector += chunk_sectors;
280 head = 0; 296 head = 0;
@@ -288,6 +304,29 @@ fail:
288 return res; 304 return res;
289} 305}
290 306
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
291 330
292static irqreturn_t ps3flash_interrupt(int irq, void *data) 331static irqreturn_t ps3flash_interrupt(int irq, void *data)
293{ 332{
@@ -312,12 +351,16 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
312 return IRQ_HANDLED; 351 return IRQ_HANDLED;
313} 352}
314 353
315
316static const struct file_operations ps3flash_fops = { 354static const struct file_operations ps3flash_fops = {
317 .owner = THIS_MODULE, 355 .owner = THIS_MODULE,
318 .llseek = ps3flash_llseek, 356 .llseek = ps3flash_llseek,
319 .read = ps3flash_read, 357 .read = ps3flash_user_read,
320 .write = ps3flash_write, 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,
321}; 364};
322 365
323static struct miscdevice ps3flash_misc = { 366static struct miscdevice ps3flash_misc = {
@@ -386,6 +429,8 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
386 429
387 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", 430 dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
388 __func__, __LINE__, ps3flash_misc.minor); 431 __func__, __LINE__, ps3flash_misc.minor);
432
433 ps3_os_area_flash_register(&ps3flash_kernel_ops);
389 return 0; 434 return 0;
390 435
391fail_teardown: 436fail_teardown:
@@ -402,6 +447,7 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
402{ 447{
403 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); 448 struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
404 449
450 ps3_os_area_flash_register(NULL);
405 misc_deregister(&ps3flash_misc); 451 misc_deregister(&ps3flash_misc);
406 ps3stor_teardown(dev); 452 ps3stor_teardown(dev);
407 kfree(ps3_system_bus_get_drvdata(&dev->sbd)); 453 kfree(ps3_system_bus_get_drvdata(&dev->sbd));