diff options
author | Paul Mackerras <paulus@samba.org> | 2007-04-23 21:45:03 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-04-23 21:45:03 -0400 |
commit | 13177c8b7eaf7ab238e79533c746153ae116f5f8 (patch) | |
tree | 4a4675749672f201c23d6df82ee2b39eedff76f2 /arch | |
parent | 445c9b5507b9d09a2e9b0b4dbb16517708aa40e6 (diff) | |
parent | ccf17e9d008dfebbf90dfa4ee1a56e81c784c73e (diff) |
Merge branch 'spufs' of master.kernel.org:/pub/scm/linux/kernel/git/arnd/cell-2.6 into for-2.6.22
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 161 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_coredump.c | 34 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/backing_ops.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 45 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/coredump.c | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/fault.c | 211 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 152 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/hw_ops.c | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 42 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/run.c | 123 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 109 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 34 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/switch.c | 8 |
14 files changed, 589 insertions, 366 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index eba7a2641dce..8086eb1ed60d 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <asm/xmon.h> | 36 | #include <asm/xmon.h> |
37 | 37 | ||
38 | const struct spu_management_ops *spu_management_ops; | 38 | const struct spu_management_ops *spu_management_ops; |
39 | EXPORT_SYMBOL_GPL(spu_management_ops); | ||
40 | |||
39 | const struct spu_priv1_ops *spu_priv1_ops; | 41 | const struct spu_priv1_ops *spu_priv1_ops; |
40 | 42 | ||
41 | static struct list_head spu_list[MAX_NUMNODES]; | 43 | static struct list_head spu_list[MAX_NUMNODES]; |
@@ -290,7 +292,6 @@ spu_irq_class_1(int irq, void *data) | |||
290 | 292 | ||
291 | return stat ? IRQ_HANDLED : IRQ_NONE; | 293 | return stat ? IRQ_HANDLED : IRQ_NONE; |
292 | } | 294 | } |
293 | EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom); | ||
294 | 295 | ||
295 | static irqreturn_t | 296 | static irqreturn_t |
296 | spu_irq_class_2(int irq, void *data) | 297 | spu_irq_class_2(int irq, void *data) |
@@ -431,10 +432,11 @@ struct spu *spu_alloc_node(int node) | |||
431 | spu = list_entry(spu_list[node].next, struct spu, list); | 432 | spu = list_entry(spu_list[node].next, struct spu, list); |
432 | list_del_init(&spu->list); | 433 | list_del_init(&spu->list); |
433 | pr_debug("Got SPU %d %d\n", spu->number, spu->node); | 434 | pr_debug("Got SPU %d %d\n", spu->number, spu->node); |
434 | spu_init_channels(spu); | ||
435 | } | 435 | } |
436 | mutex_unlock(&spu_mutex); | 436 | mutex_unlock(&spu_mutex); |
437 | 437 | ||
438 | if (spu) | ||
439 | spu_init_channels(spu); | ||
438 | return spu; | 440 | return spu; |
439 | } | 441 | } |
440 | EXPORT_SYMBOL_GPL(spu_alloc_node); | 442 | EXPORT_SYMBOL_GPL(spu_alloc_node); |
@@ -461,108 +463,6 @@ void spu_free(struct spu *spu) | |||
461 | } | 463 | } |
462 | EXPORT_SYMBOL_GPL(spu_free); | 464 | EXPORT_SYMBOL_GPL(spu_free); |
463 | 465 | ||
464 | static int spu_handle_mm_fault(struct spu *spu) | ||
465 | { | ||
466 | struct mm_struct *mm = spu->mm; | ||
467 | struct vm_area_struct *vma; | ||
468 | u64 ea, dsisr, is_write; | ||
469 | int ret; | ||
470 | |||
471 | ea = spu->dar; | ||
472 | dsisr = spu->dsisr; | ||
473 | #if 0 | ||
474 | if (!IS_VALID_EA(ea)) { | ||
475 | return -EFAULT; | ||
476 | } | ||
477 | #endif /* XXX */ | ||
478 | if (mm == NULL) { | ||
479 | return -EFAULT; | ||
480 | } | ||
481 | if (mm->pgd == NULL) { | ||
482 | return -EFAULT; | ||
483 | } | ||
484 | |||
485 | down_read(&mm->mmap_sem); | ||
486 | vma = find_vma(mm, ea); | ||
487 | if (!vma) | ||
488 | goto bad_area; | ||
489 | if (vma->vm_start <= ea) | ||
490 | goto good_area; | ||
491 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
492 | goto bad_area; | ||
493 | #if 0 | ||
494 | if (expand_stack(vma, ea)) | ||
495 | goto bad_area; | ||
496 | #endif /* XXX */ | ||
497 | good_area: | ||
498 | is_write = dsisr & MFC_DSISR_ACCESS_PUT; | ||
499 | if (is_write) { | ||
500 | if (!(vma->vm_flags & VM_WRITE)) | ||
501 | goto bad_area; | ||
502 | } else { | ||
503 | if (dsisr & MFC_DSISR_ACCESS_DENIED) | ||
504 | goto bad_area; | ||
505 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | ||
506 | goto bad_area; | ||
507 | } | ||
508 | ret = 0; | ||
509 | switch (handle_mm_fault(mm, vma, ea, is_write)) { | ||
510 | case VM_FAULT_MINOR: | ||
511 | current->min_flt++; | ||
512 | break; | ||
513 | case VM_FAULT_MAJOR: | ||
514 | current->maj_flt++; | ||
515 | break; | ||
516 | case VM_FAULT_SIGBUS: | ||
517 | ret = -EFAULT; | ||
518 | goto bad_area; | ||
519 | case VM_FAULT_OOM: | ||
520 | ret = -ENOMEM; | ||
521 | goto bad_area; | ||
522 | default: | ||
523 | BUG(); | ||
524 | } | ||
525 | up_read(&mm->mmap_sem); | ||
526 | return ret; | ||
527 | |||
528 | bad_area: | ||
529 | up_read(&mm->mmap_sem); | ||
530 | return -EFAULT; | ||
531 | } | ||
532 | |||
533 | int spu_irq_class_1_bottom(struct spu *spu) | ||
534 | { | ||
535 | u64 ea, dsisr, access, error = 0UL; | ||
536 | int ret = 0; | ||
537 | |||
538 | ea = spu->dar; | ||
539 | dsisr = spu->dsisr; | ||
540 | if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) { | ||
541 | u64 flags; | ||
542 | |||
543 | access = (_PAGE_PRESENT | _PAGE_USER); | ||
544 | access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; | ||
545 | local_irq_save(flags); | ||
546 | if (hash_page(ea, access, 0x300) != 0) | ||
547 | error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; | ||
548 | local_irq_restore(flags); | ||
549 | } | ||
550 | if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) { | ||
551 | if ((ret = spu_handle_mm_fault(spu)) != 0) | ||
552 | error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; | ||
553 | else | ||
554 | error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR; | ||
555 | } | ||
556 | spu->dar = 0UL; | ||
557 | spu->dsisr = 0UL; | ||
558 | if (!error) { | ||
559 | spu_restart_dma(spu); | ||
560 | } else { | ||
561 | spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE); | ||
562 | } | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | struct sysdev_class spu_sysdev_class = { | 466 | struct sysdev_class spu_sysdev_class = { |
567 | set_kset_name("spu") | 467 | set_kset_name("spu") |
568 | }; | 468 | }; |
@@ -636,12 +536,6 @@ static int spu_create_sysdev(struct spu *spu) | |||
636 | return 0; | 536 | return 0; |
637 | } | 537 | } |
638 | 538 | ||
639 | static void spu_destroy_sysdev(struct spu *spu) | ||
640 | { | ||
641 | sysfs_remove_device_from_node(&spu->sysdev, spu->node); | ||
642 | sysdev_unregister(&spu->sysdev); | ||
643 | } | ||
644 | |||
645 | static int __init create_spu(void *data) | 539 | static int __init create_spu(void *data) |
646 | { | 540 | { |
647 | struct spu *spu; | 541 | struct spu *spu; |
@@ -693,58 +587,37 @@ out: | |||
693 | return ret; | 587 | return ret; |
694 | } | 588 | } |
695 | 589 | ||
696 | static void destroy_spu(struct spu *spu) | ||
697 | { | ||
698 | list_del_init(&spu->list); | ||
699 | list_del_init(&spu->full_list); | ||
700 | |||
701 | spu_destroy_sysdev(spu); | ||
702 | spu_free_irqs(spu); | ||
703 | spu_destroy_spu(spu); | ||
704 | kfree(spu); | ||
705 | } | ||
706 | |||
707 | static void cleanup_spu_base(void) | ||
708 | { | ||
709 | struct spu *spu, *tmp; | ||
710 | int node; | ||
711 | |||
712 | mutex_lock(&spu_mutex); | ||
713 | for (node = 0; node < MAX_NUMNODES; node++) { | ||
714 | list_for_each_entry_safe(spu, tmp, &spu_list[node], list) | ||
715 | destroy_spu(spu); | ||
716 | } | ||
717 | mutex_unlock(&spu_mutex); | ||
718 | sysdev_class_unregister(&spu_sysdev_class); | ||
719 | } | ||
720 | module_exit(cleanup_spu_base); | ||
721 | |||
722 | static int __init init_spu_base(void) | 590 | static int __init init_spu_base(void) |
723 | { | 591 | { |
724 | int i, ret; | 592 | int i, ret = 0; |
593 | |||
594 | for (i = 0; i < MAX_NUMNODES; i++) | ||
595 | INIT_LIST_HEAD(&spu_list[i]); | ||
725 | 596 | ||
726 | if (!spu_management_ops) | 597 | if (!spu_management_ops) |
727 | return 0; | 598 | goto out; |
728 | 599 | ||
729 | /* create sysdev class for spus */ | 600 | /* create sysdev class for spus */ |
730 | ret = sysdev_class_register(&spu_sysdev_class); | 601 | ret = sysdev_class_register(&spu_sysdev_class); |
731 | if (ret) | 602 | if (ret) |
732 | return ret; | 603 | goto out; |
733 | |||
734 | for (i = 0; i < MAX_NUMNODES; i++) | ||
735 | INIT_LIST_HEAD(&spu_list[i]); | ||
736 | 604 | ||
737 | ret = spu_enumerate_spus(create_spu); | 605 | ret = spu_enumerate_spus(create_spu); |
738 | 606 | ||
739 | if (ret) { | 607 | if (ret) { |
740 | printk(KERN_WARNING "%s: Error initializing spus\n", | 608 | printk(KERN_WARNING "%s: Error initializing spus\n", |
741 | __FUNCTION__); | 609 | __FUNCTION__); |
742 | cleanup_spu_base(); | 610 | goto out_unregister_sysdev_class; |
743 | return ret; | ||
744 | } | 611 | } |
745 | 612 | ||
746 | xmon_register_spus(&spu_full_list); | 613 | xmon_register_spus(&spu_full_list); |
747 | 614 | ||
615 | return 0; | ||
616 | |||
617 | out_unregister_sysdev_class: | ||
618 | sysdev_class_unregister(&spu_sysdev_class); | ||
619 | out: | ||
620 | |||
748 | return ret; | 621 | return ret; |
749 | } | 622 | } |
750 | module_init(init_spu_base); | 623 | module_init(init_spu_base); |
diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c index 6915b418ee73..4fd37ff1e210 100644 --- a/arch/powerpc/platforms/cell/spu_coredump.c +++ b/arch/powerpc/platforms/cell/spu_coredump.c | |||
@@ -26,19 +26,18 @@ | |||
26 | 26 | ||
27 | #include <asm/spu.h> | 27 | #include <asm/spu.h> |
28 | 28 | ||
29 | static struct spu_coredump_calls spu_coredump_calls; | 29 | static struct spu_coredump_calls *spu_coredump_calls; |
30 | static DEFINE_MUTEX(spu_coredump_mutex); | 30 | static DEFINE_MUTEX(spu_coredump_mutex); |
31 | 31 | ||
32 | int arch_notes_size(void) | 32 | int arch_notes_size(void) |
33 | { | 33 | { |
34 | long ret; | 34 | long ret; |
35 | struct module *owner = spu_coredump_calls.owner; | ||
36 | 35 | ||
37 | ret = -ENOSYS; | 36 | ret = -ENOSYS; |
38 | mutex_lock(&spu_coredump_mutex); | 37 | mutex_lock(&spu_coredump_mutex); |
39 | if (owner && try_module_get(owner)) { | 38 | if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { |
40 | ret = spu_coredump_calls.arch_notes_size(); | 39 | ret = spu_coredump_calls->arch_notes_size(); |
41 | module_put(owner); | 40 | module_put(spu_coredump_calls->owner); |
42 | } | 41 | } |
43 | mutex_unlock(&spu_coredump_mutex); | 42 | mutex_unlock(&spu_coredump_mutex); |
44 | return ret; | 43 | return ret; |
@@ -46,36 +45,35 @@ int arch_notes_size(void) | |||
46 | 45 | ||
47 | void arch_write_notes(struct file *file) | 46 | void arch_write_notes(struct file *file) |
48 | { | 47 | { |
49 | struct module *owner = spu_coredump_calls.owner; | ||
50 | |||
51 | mutex_lock(&spu_coredump_mutex); | 48 | mutex_lock(&spu_coredump_mutex); |
52 | if (owner && try_module_get(owner)) { | 49 | if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) { |
53 | spu_coredump_calls.arch_write_notes(file); | 50 | spu_coredump_calls->arch_write_notes(file); |
54 | module_put(owner); | 51 | module_put(spu_coredump_calls->owner); |
55 | } | 52 | } |
56 | mutex_unlock(&spu_coredump_mutex); | 53 | mutex_unlock(&spu_coredump_mutex); |
57 | } | 54 | } |
58 | 55 | ||
59 | int register_arch_coredump_calls(struct spu_coredump_calls *calls) | 56 | int register_arch_coredump_calls(struct spu_coredump_calls *calls) |
60 | { | 57 | { |
61 | if (spu_coredump_calls.owner) | 58 | int ret = 0; |
62 | return -EBUSY; | 59 | |
63 | 60 | ||
64 | mutex_lock(&spu_coredump_mutex); | 61 | mutex_lock(&spu_coredump_mutex); |
65 | spu_coredump_calls.arch_notes_size = calls->arch_notes_size; | 62 | if (spu_coredump_calls) |
66 | spu_coredump_calls.arch_write_notes = calls->arch_write_notes; | 63 | ret = -EBUSY; |
67 | spu_coredump_calls.owner = calls->owner; | 64 | else |
65 | spu_coredump_calls = calls; | ||
68 | mutex_unlock(&spu_coredump_mutex); | 66 | mutex_unlock(&spu_coredump_mutex); |
69 | return 0; | 67 | return ret; |
70 | } | 68 | } |
71 | EXPORT_SYMBOL_GPL(register_arch_coredump_calls); | 69 | EXPORT_SYMBOL_GPL(register_arch_coredump_calls); |
72 | 70 | ||
73 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) | 71 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) |
74 | { | 72 | { |
75 | BUG_ON(spu_coredump_calls.owner != calls->owner); | 73 | BUG_ON(spu_coredump_calls != calls); |
76 | 74 | ||
77 | mutex_lock(&spu_coredump_mutex); | 75 | mutex_lock(&spu_coredump_mutex); |
78 | spu_coredump_calls.owner = NULL; | 76 | spu_coredump_calls = NULL; |
79 | mutex_unlock(&spu_coredump_mutex); | 77 | mutex_unlock(&spu_coredump_mutex); |
80 | } | 78 | } |
81 | EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); | 79 | EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); |
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index 472217d19faf..2cd89c11af5a 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-y += switch.o | 1 | obj-y += switch.o fault.o |
2 | 2 | ||
3 | obj-$(CONFIG_SPU_FS) += spufs.o | 3 | obj-$(CONFIG_SPU_FS) += spufs.o |
4 | spufs-y += inode.o file.o context.o syscalls.o coredump.o | 4 | spufs-y += inode.o file.o context.o syscalls.o coredump.o |
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index 1898f0d3a8b8..3322528fa6eb 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c | |||
@@ -350,6 +350,11 @@ static int spu_backing_send_mfc_command(struct spu_context *ctx, | |||
350 | return ret; | 350 | return ret; |
351 | } | 351 | } |
352 | 352 | ||
353 | static void spu_backing_restart_dma(struct spu_context *ctx) | ||
354 | { | ||
355 | /* nothing to do here */ | ||
356 | } | ||
357 | |||
353 | struct spu_context_ops spu_backing_ops = { | 358 | struct spu_context_ops spu_backing_ops = { |
354 | .mbox_read = spu_backing_mbox_read, | 359 | .mbox_read = spu_backing_mbox_read, |
355 | .mbox_stat_read = spu_backing_mbox_stat_read, | 360 | .mbox_stat_read = spu_backing_mbox_stat_read, |
@@ -376,4 +381,5 @@ struct spu_context_ops spu_backing_ops = { | |||
376 | .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus, | 381 | .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus, |
377 | .get_mfc_free_elements = spu_backing_get_mfc_free_elements, | 382 | .get_mfc_free_elements = spu_backing_get_mfc_free_elements, |
378 | .send_mfc_command = spu_backing_send_mfc_command, | 383 | .send_mfc_command = spu_backing_send_mfc_command, |
384 | .restart_dma = spu_backing_restart_dma, | ||
379 | }; | 385 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 04ad2e364e97..a87d9ca3dba2 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -41,9 +41,10 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
41 | goto out_free; | 41 | goto out_free; |
42 | } | 42 | } |
43 | spin_lock_init(&ctx->mmio_lock); | 43 | spin_lock_init(&ctx->mmio_lock); |
44 | spin_lock_init(&ctx->mapping_lock); | ||
44 | kref_init(&ctx->kref); | 45 | kref_init(&ctx->kref); |
45 | mutex_init(&ctx->state_mutex); | 46 | mutex_init(&ctx->state_mutex); |
46 | init_MUTEX(&ctx->run_sema); | 47 | mutex_init(&ctx->run_mutex); |
47 | init_waitqueue_head(&ctx->ibox_wq); | 48 | init_waitqueue_head(&ctx->ibox_wq); |
48 | init_waitqueue_head(&ctx->wbox_wq); | 49 | init_waitqueue_head(&ctx->wbox_wq); |
49 | init_waitqueue_head(&ctx->stop_wq); | 50 | init_waitqueue_head(&ctx->stop_wq); |
@@ -51,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
51 | ctx->state = SPU_STATE_SAVED; | 52 | ctx->state = SPU_STATE_SAVED; |
52 | ctx->ops = &spu_backing_ops; | 53 | ctx->ops = &spu_backing_ops; |
53 | ctx->owner = get_task_mm(current); | 54 | ctx->owner = get_task_mm(current); |
55 | INIT_LIST_HEAD(&ctx->rq); | ||
54 | if (gang) | 56 | if (gang) |
55 | spu_gang_add_ctx(gang, ctx); | 57 | spu_gang_add_ctx(gang, ctx); |
56 | ctx->rt_priority = current->rt_priority; | 58 | ctx->rt_priority = current->rt_priority; |
@@ -75,6 +77,7 @@ void destroy_spu_context(struct kref *kref) | |||
75 | spu_fini_csa(&ctx->csa); | 77 | spu_fini_csa(&ctx->csa); |
76 | if (ctx->gang) | 78 | if (ctx->gang) |
77 | spu_gang_remove_ctx(ctx->gang, ctx); | 79 | spu_gang_remove_ctx(ctx->gang, ctx); |
80 | BUG_ON(!list_empty(&ctx->rq)); | ||
78 | kfree(ctx); | 81 | kfree(ctx); |
79 | } | 82 | } |
80 | 83 | ||
@@ -119,46 +122,6 @@ void spu_unmap_mappings(struct spu_context *ctx) | |||
119 | } | 122 | } |
120 | 123 | ||
121 | /** | 124 | /** |
122 | * spu_acquire_exclusive - lock spu contex and protect against userspace access | ||
123 | * @ctx: spu contex to lock | ||
124 | * | ||
125 | * Note: | ||
126 | * Returns 0 and with the context locked on success | ||
127 | * Returns negative error and with the context _unlocked_ on failure. | ||
128 | */ | ||
129 | int spu_acquire_exclusive(struct spu_context *ctx) | ||
130 | { | ||
131 | int ret = -EINVAL; | ||
132 | |||
133 | spu_acquire(ctx); | ||
134 | /* | ||
135 | * Context is about to be freed, so we can't acquire it anymore. | ||
136 | */ | ||
137 | if (!ctx->owner) | ||
138 | goto out_unlock; | ||
139 | |||
140 | if (ctx->state == SPU_STATE_SAVED) { | ||
141 | ret = spu_activate(ctx, 0); | ||
142 | if (ret) | ||
143 | goto out_unlock; | ||
144 | } else { | ||
145 | /* | ||
146 | * We need to exclude userspace access to the context. | ||
147 | * | ||
148 | * To protect against memory access we invalidate all ptes | ||
149 | * and make sure the pagefault handlers block on the mutex. | ||
150 | */ | ||
151 | spu_unmap_mappings(ctx); | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | |||
156 | out_unlock: | ||
157 | spu_release(ctx); | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * spu_acquire_runnable - lock spu contex and make sure it is in runnable state | 125 | * spu_acquire_runnable - lock spu contex and make sure it is in runnable state |
163 | * @ctx: spu contex to lock | 126 | * @ctx: spu contex to lock |
164 | * | 127 | * |
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 725e19561159..5d9ad5a0307b 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c | |||
@@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, | |||
169 | struct spu_context *ctx; | 169 | struct spu_context *ctx; |
170 | loff_t pos = 0; | 170 | loff_t pos = 0; |
171 | int sz, dfd, rc, total = 0; | 171 | int sz, dfd, rc, total = 0; |
172 | const int bufsz = 4096; | 172 | const int bufsz = PAGE_SIZE; |
173 | char *name; | 173 | char *name; |
174 | char fullname[80], *buf; | 174 | char fullname[80], *buf; |
175 | struct elf_note en; | 175 | struct elf_note en; |
176 | 176 | ||
177 | buf = kmalloc(bufsz, GFP_KERNEL); | 177 | buf = (void *)get_zeroed_page(GFP_KERNEL); |
178 | if (!buf) | 178 | if (!buf) |
179 | return; | 179 | return; |
180 | 180 | ||
@@ -187,9 +187,8 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, | |||
187 | sz = spufs_coredump_read[i].size; | 187 | sz = spufs_coredump_read[i].size; |
188 | 188 | ||
189 | ctx = ctx_info->ctx; | 189 | ctx = ctx_info->ctx; |
190 | if (!ctx) { | 190 | if (!ctx) |
191 | return; | 191 | goto out; |
192 | } | ||
193 | 192 | ||
194 | sprintf(fullname, "SPU/%d/%s", dfd, name); | 193 | sprintf(fullname, "SPU/%d/%s", dfd, name); |
195 | en.n_namesz = strlen(fullname) + 1; | 194 | en.n_namesz = strlen(fullname) + 1; |
@@ -197,23 +196,25 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, | |||
197 | en.n_type = NT_SPU; | 196 | en.n_type = NT_SPU; |
198 | 197 | ||
199 | if (!spufs_dump_write(file, &en, sizeof(en))) | 198 | if (!spufs_dump_write(file, &en, sizeof(en))) |
200 | return; | 199 | goto out; |
201 | if (!spufs_dump_write(file, fullname, en.n_namesz)) | 200 | if (!spufs_dump_write(file, fullname, en.n_namesz)) |
202 | return; | 201 | goto out; |
203 | if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) | 202 | if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) |
204 | return; | 203 | goto out; |
205 | 204 | ||
206 | do { | 205 | do { |
207 | rc = do_coredump_read(i, ctx, buf, bufsz, &pos); | 206 | rc = do_coredump_read(i, ctx, buf, bufsz, &pos); |
208 | if (rc > 0) { | 207 | if (rc > 0) { |
209 | if (!spufs_dump_write(file, buf, rc)) | 208 | if (!spufs_dump_write(file, buf, rc)) |
210 | return; | 209 | goto out; |
211 | total += rc; | 210 | total += rc; |
212 | } | 211 | } |
213 | } while (rc == bufsz && total < sz); | 212 | } while (rc == bufsz && total < sz); |
214 | 213 | ||
215 | spufs_dump_seek(file, roundup((unsigned long)file->f_pos | 214 | spufs_dump_seek(file, roundup((unsigned long)file->f_pos |
216 | - total + sz, 4)); | 215 | - total + sz, 4)); |
216 | out: | ||
217 | free_page((unsigned long)buf); | ||
217 | } | 218 | } |
218 | 219 | ||
219 | static void spufs_arch_write_notes(struct file *file) | 220 | static void spufs_arch_write_notes(struct file *file) |
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c new file mode 100644 index 000000000000..0f75c07e29d8 --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/fault.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Low-level SPU handling | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | ||
5 | * | ||
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <asm/spu.h> | ||
27 | #include <asm/spu_csa.h> | ||
28 | |||
29 | #include "spufs.h" | ||
30 | |||
31 | /* | ||
32 | * This ought to be kept in sync with the powerpc specific do_page_fault | ||
33 | * function. Currently, there are a few corner cases that we haven't had | ||
34 | * to handle fortunately. | ||
35 | */ | ||
36 | static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr) | ||
37 | { | ||
38 | struct vm_area_struct *vma; | ||
39 | unsigned long is_write; | ||
40 | int ret; | ||
41 | |||
42 | #if 0 | ||
43 | if (!IS_VALID_EA(ea)) { | ||
44 | return -EFAULT; | ||
45 | } | ||
46 | #endif /* XXX */ | ||
47 | if (mm == NULL) { | ||
48 | return -EFAULT; | ||
49 | } | ||
50 | if (mm->pgd == NULL) { | ||
51 | return -EFAULT; | ||
52 | } | ||
53 | |||
54 | down_read(&mm->mmap_sem); | ||
55 | vma = find_vma(mm, ea); | ||
56 | if (!vma) | ||
57 | goto bad_area; | ||
58 | if (vma->vm_start <= ea) | ||
59 | goto good_area; | ||
60 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
61 | goto bad_area; | ||
62 | if (expand_stack(vma, ea)) | ||
63 | goto bad_area; | ||
64 | good_area: | ||
65 | is_write = dsisr & MFC_DSISR_ACCESS_PUT; | ||
66 | if (is_write) { | ||
67 | if (!(vma->vm_flags & VM_WRITE)) | ||
68 | goto bad_area; | ||
69 | } else { | ||
70 | if (dsisr & MFC_DSISR_ACCESS_DENIED) | ||
71 | goto bad_area; | ||
72 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | ||
73 | goto bad_area; | ||
74 | } | ||
75 | ret = 0; | ||
76 | switch (handle_mm_fault(mm, vma, ea, is_write)) { | ||
77 | case VM_FAULT_MINOR: | ||
78 | current->min_flt++; | ||
79 | break; | ||
80 | case VM_FAULT_MAJOR: | ||
81 | current->maj_flt++; | ||
82 | break; | ||
83 | case VM_FAULT_SIGBUS: | ||
84 | ret = -EFAULT; | ||
85 | goto bad_area; | ||
86 | case VM_FAULT_OOM: | ||
87 | ret = -ENOMEM; | ||
88 | goto bad_area; | ||
89 | default: | ||
90 | BUG(); | ||
91 | } | ||
92 | up_read(&mm->mmap_sem); | ||
93 | return ret; | ||
94 | |||
95 | bad_area: | ||
96 | up_read(&mm->mmap_sem); | ||
97 | return -EFAULT; | ||
98 | } | ||
99 | |||
100 | static void spufs_handle_dma_error(struct spu_context *ctx, | ||
101 | unsigned long ea, int type) | ||
102 | { | ||
103 | if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { | ||
104 | ctx->event_return |= type; | ||
105 | wake_up_all(&ctx->stop_wq); | ||
106 | } else { | ||
107 | siginfo_t info; | ||
108 | memset(&info, 0, sizeof(info)); | ||
109 | |||
110 | switch (type) { | ||
111 | case SPE_EVENT_INVALID_DMA: | ||
112 | info.si_signo = SIGBUS; | ||
113 | info.si_code = BUS_OBJERR; | ||
114 | break; | ||
115 | case SPE_EVENT_SPE_DATA_STORAGE: | ||
116 | info.si_signo = SIGBUS; | ||
117 | info.si_addr = (void __user *)ea; | ||
118 | info.si_code = BUS_ADRERR; | ||
119 | break; | ||
120 | case SPE_EVENT_DMA_ALIGNMENT: | ||
121 | info.si_signo = SIGBUS; | ||
122 | /* DAR isn't set for an alignment fault :( */ | ||
123 | info.si_code = BUS_ADRALN; | ||
124 | break; | ||
125 | case SPE_EVENT_SPE_ERROR: | ||
126 | info.si_signo = SIGILL; | ||
127 | info.si_addr = (void __user *)(unsigned long) | ||
128 | ctx->ops->npc_read(ctx) - 4; | ||
129 | info.si_code = ILL_ILLOPC; | ||
130 | break; | ||
131 | } | ||
132 | if (info.si_signo) | ||
133 | force_sig_info(info.si_signo, &info, current); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | void spufs_dma_callback(struct spu *spu, int type) | ||
138 | { | ||
139 | spufs_handle_dma_error(spu->ctx, spu->dar, type); | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(spufs_dma_callback); | ||
142 | |||
143 | /* | ||
144 | * bottom half handler for page faults, we can't do this from | ||
145 | * interrupt context, since we might need to sleep. | ||
146 | * we also need to give up the mutex so we can get scheduled | ||
147 | * out while waiting for the backing store. | ||
148 | * | ||
149 | * TODO: try calling hash_page from the interrupt handler first | ||
150 | * in order to speed up the easy case. | ||
151 | */ | ||
152 | int spufs_handle_class1(struct spu_context *ctx) | ||
153 | { | ||
154 | u64 ea, dsisr, access; | ||
155 | unsigned long flags; | ||
156 | int ret; | ||
157 | |||
158 | /* | ||
159 | * dar and dsisr get passed from the registers | ||
160 | * to the spu_context, to this function, but not | ||
161 | * back to the spu if it gets scheduled again. | ||
162 | * | ||
163 | * if we don't handle the fault for a saved context | ||
164 | * in time, we can still expect to get the same fault | ||
165 | * the immediately after the context restore. | ||
166 | */ | ||
167 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
168 | ea = ctx->spu->dar; | ||
169 | dsisr = ctx->spu->dsisr; | ||
170 | ctx->spu->dar= ctx->spu->dsisr = 0; | ||
171 | } else { | ||
172 | ea = ctx->csa.priv1.mfc_dar_RW; | ||
173 | dsisr = ctx->csa.priv1.mfc_dsisr_RW; | ||
174 | ctx->csa.priv1.mfc_dar_RW = 0; | ||
175 | ctx->csa.priv1.mfc_dsisr_RW = 0; | ||
176 | } | ||
177 | |||
178 | if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) | ||
179 | return 0; | ||
180 | |||
181 | pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, | ||
182 | dsisr, ctx->state); | ||
183 | |||
184 | /* we must not hold the lock when entering spu_handle_mm_fault */ | ||
185 | spu_release(ctx); | ||
186 | |||
187 | access = (_PAGE_PRESENT | _PAGE_USER); | ||
188 | access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; | ||
189 | local_irq_save(flags); | ||
190 | ret = hash_page(ea, access, 0x300); | ||
191 | local_irq_restore(flags); | ||
192 | |||
193 | /* hashing failed, so try the actual fault handler */ | ||
194 | if (ret) | ||
195 | ret = spu_handle_mm_fault(current->mm, ea, dsisr); | ||
196 | |||
197 | spu_acquire(ctx); | ||
198 | /* | ||
199 | * If we handled the fault successfully and are in runnable | ||
200 | * state, restart the DMA. | ||
201 | * In case of unhandled error report the problem to user space. | ||
202 | */ | ||
203 | if (!ret) { | ||
204 | if (ctx->spu) | ||
205 | ctx->ops->restart_dma(ctx); | ||
206 | } else | ||
207 | spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); | ||
208 | |||
209 | return ret; | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(spufs_handle_class1); | ||
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 505266a568d4..d010b2464a98 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, struct file *file) | |||
44 | { | 44 | { |
45 | struct spufs_inode_info *i = SPUFS_I(inode); | 45 | struct spufs_inode_info *i = SPUFS_I(inode); |
46 | struct spu_context *ctx = i->i_ctx; | 46 | struct spu_context *ctx = i->i_ctx; |
47 | |||
48 | spin_lock(&ctx->mapping_lock); | ||
47 | file->private_data = ctx; | 49 | file->private_data = ctx; |
48 | ctx->local_store = inode->i_mapping; | 50 | if (!i->i_openers++) |
49 | smp_wmb(); | 51 | ctx->local_store = inode->i_mapping; |
52 | spin_unlock(&ctx->mapping_lock); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | spufs_mem_release(struct inode *inode, struct file *file) | ||
58 | { | ||
59 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
60 | struct spu_context *ctx = i->i_ctx; | ||
61 | |||
62 | spin_lock(&ctx->mapping_lock); | ||
63 | if (!--i->i_openers) | ||
64 | ctx->local_store = NULL; | ||
65 | spin_unlock(&ctx->mapping_lock); | ||
50 | return 0; | 66 | return 0; |
51 | } | 67 | } |
52 | 68 | ||
@@ -149,6 +165,7 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) | |||
149 | 165 | ||
150 | static const struct file_operations spufs_mem_fops = { | 166 | static const struct file_operations spufs_mem_fops = { |
151 | .open = spufs_mem_open, | 167 | .open = spufs_mem_open, |
168 | .release = spufs_mem_release, | ||
152 | .read = spufs_mem_read, | 169 | .read = spufs_mem_read, |
153 | .write = spufs_mem_write, | 170 | .write = spufs_mem_write, |
154 | .llseek = generic_file_llseek, | 171 | .llseek = generic_file_llseek, |
@@ -238,16 +255,33 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) | |||
238 | struct spufs_inode_info *i = SPUFS_I(inode); | 255 | struct spufs_inode_info *i = SPUFS_I(inode); |
239 | struct spu_context *ctx = i->i_ctx; | 256 | struct spu_context *ctx = i->i_ctx; |
240 | 257 | ||
258 | spin_lock(&ctx->mapping_lock); | ||
241 | file->private_data = ctx; | 259 | file->private_data = ctx; |
242 | ctx->cntl = inode->i_mapping; | 260 | if (!i->i_openers++) |
243 | smp_wmb(); | 261 | ctx->cntl = inode->i_mapping; |
262 | spin_unlock(&ctx->mapping_lock); | ||
244 | return simple_attr_open(inode, file, spufs_cntl_get, | 263 | return simple_attr_open(inode, file, spufs_cntl_get, |
245 | spufs_cntl_set, "0x%08lx"); | 264 | spufs_cntl_set, "0x%08lx"); |
246 | } | 265 | } |
247 | 266 | ||
267 | static int | ||
268 | spufs_cntl_release(struct inode *inode, struct file *file) | ||
269 | { | ||
270 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
271 | struct spu_context *ctx = i->i_ctx; | ||
272 | |||
273 | simple_attr_close(inode, file); | ||
274 | |||
275 | spin_lock(&ctx->mapping_lock); | ||
276 | if (!--i->i_openers) | ||
277 | ctx->cntl = NULL; | ||
278 | spin_unlock(&ctx->mapping_lock); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
248 | static const struct file_operations spufs_cntl_fops = { | 282 | static const struct file_operations spufs_cntl_fops = { |
249 | .open = spufs_cntl_open, | 283 | .open = spufs_cntl_open, |
250 | .release = simple_attr_close, | 284 | .release = spufs_cntl_release, |
251 | .read = simple_attr_read, | 285 | .read = simple_attr_read, |
252 | .write = simple_attr_write, | 286 | .write = simple_attr_write, |
253 | .mmap = spufs_cntl_mmap, | 287 | .mmap = spufs_cntl_mmap, |
@@ -723,12 +757,28 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) | |||
723 | { | 757 | { |
724 | struct spufs_inode_info *i = SPUFS_I(inode); | 758 | struct spufs_inode_info *i = SPUFS_I(inode); |
725 | struct spu_context *ctx = i->i_ctx; | 759 | struct spu_context *ctx = i->i_ctx; |
760 | |||
761 | spin_lock(&ctx->mapping_lock); | ||
726 | file->private_data = ctx; | 762 | file->private_data = ctx; |
727 | ctx->signal1 = inode->i_mapping; | 763 | if (!i->i_openers++) |
728 | smp_wmb(); | 764 | ctx->signal1 = inode->i_mapping; |
765 | spin_unlock(&ctx->mapping_lock); | ||
729 | return nonseekable_open(inode, file); | 766 | return nonseekable_open(inode, file); |
730 | } | 767 | } |
731 | 768 | ||
769 | static int | ||
770 | spufs_signal1_release(struct inode *inode, struct file *file) | ||
771 | { | ||
772 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
773 | struct spu_context *ctx = i->i_ctx; | ||
774 | |||
775 | spin_lock(&ctx->mapping_lock); | ||
776 | if (!--i->i_openers) | ||
777 | ctx->signal1 = NULL; | ||
778 | spin_unlock(&ctx->mapping_lock); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
732 | static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, | 782 | static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, |
733 | size_t len, loff_t *pos) | 783 | size_t len, loff_t *pos) |
734 | { | 784 | { |
@@ -821,6 +871,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) | |||
821 | 871 | ||
822 | static const struct file_operations spufs_signal1_fops = { | 872 | static const struct file_operations spufs_signal1_fops = { |
823 | .open = spufs_signal1_open, | 873 | .open = spufs_signal1_open, |
874 | .release = spufs_signal1_release, | ||
824 | .read = spufs_signal1_read, | 875 | .read = spufs_signal1_read, |
825 | .write = spufs_signal1_write, | 876 | .write = spufs_signal1_write, |
826 | .mmap = spufs_signal1_mmap, | 877 | .mmap = spufs_signal1_mmap, |
@@ -830,12 +881,28 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) | |||
830 | { | 881 | { |
831 | struct spufs_inode_info *i = SPUFS_I(inode); | 882 | struct spufs_inode_info *i = SPUFS_I(inode); |
832 | struct spu_context *ctx = i->i_ctx; | 883 | struct spu_context *ctx = i->i_ctx; |
884 | |||
885 | spin_lock(&ctx->mapping_lock); | ||
833 | file->private_data = ctx; | 886 | file->private_data = ctx; |
834 | ctx->signal2 = inode->i_mapping; | 887 | if (!i->i_openers++) |
835 | smp_wmb(); | 888 | ctx->signal2 = inode->i_mapping; |
889 | spin_unlock(&ctx->mapping_lock); | ||
836 | return nonseekable_open(inode, file); | 890 | return nonseekable_open(inode, file); |
837 | } | 891 | } |
838 | 892 | ||
893 | static int | ||
894 | spufs_signal2_release(struct inode *inode, struct file *file) | ||
895 | { | ||
896 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
897 | struct spu_context *ctx = i->i_ctx; | ||
898 | |||
899 | spin_lock(&ctx->mapping_lock); | ||
900 | if (!--i->i_openers) | ||
901 | ctx->signal2 = NULL; | ||
902 | spin_unlock(&ctx->mapping_lock); | ||
903 | return 0; | ||
904 | } | ||
905 | |||
839 | static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, | 906 | static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, |
840 | size_t len, loff_t *pos) | 907 | size_t len, loff_t *pos) |
841 | { | 908 | { |
@@ -932,6 +999,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) | |||
932 | 999 | ||
933 | static const struct file_operations spufs_signal2_fops = { | 1000 | static const struct file_operations spufs_signal2_fops = { |
934 | .open = spufs_signal2_open, | 1001 | .open = spufs_signal2_open, |
1002 | .release = spufs_signal2_release, | ||
935 | .read = spufs_signal2_read, | 1003 | .read = spufs_signal2_read, |
936 | .write = spufs_signal2_write, | 1004 | .write = spufs_signal2_write, |
937 | .mmap = spufs_signal2_mmap, | 1005 | .mmap = spufs_signal2_mmap, |
@@ -1031,13 +1099,30 @@ static int spufs_mss_open(struct inode *inode, struct file *file) | |||
1031 | struct spu_context *ctx = i->i_ctx; | 1099 | struct spu_context *ctx = i->i_ctx; |
1032 | 1100 | ||
1033 | file->private_data = i->i_ctx; | 1101 | file->private_data = i->i_ctx; |
1034 | ctx->mss = inode->i_mapping; | 1102 | |
1035 | smp_wmb(); | 1103 | spin_lock(&ctx->mapping_lock); |
1104 | if (!i->i_openers++) | ||
1105 | ctx->mss = inode->i_mapping; | ||
1106 | spin_unlock(&ctx->mapping_lock); | ||
1036 | return nonseekable_open(inode, file); | 1107 | return nonseekable_open(inode, file); |
1037 | } | 1108 | } |
1038 | 1109 | ||
1110 | static int | ||
1111 | spufs_mss_release(struct inode *inode, struct file *file) | ||
1112 | { | ||
1113 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
1114 | struct spu_context *ctx = i->i_ctx; | ||
1115 | |||
1116 | spin_lock(&ctx->mapping_lock); | ||
1117 | if (!--i->i_openers) | ||
1118 | ctx->mss = NULL; | ||
1119 | spin_unlock(&ctx->mapping_lock); | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1039 | static const struct file_operations spufs_mss_fops = { | 1123 | static const struct file_operations spufs_mss_fops = { |
1040 | .open = spufs_mss_open, | 1124 | .open = spufs_mss_open, |
1125 | .release = spufs_mss_release, | ||
1041 | .mmap = spufs_mss_mmap, | 1126 | .mmap = spufs_mss_mmap, |
1042 | }; | 1127 | }; |
1043 | 1128 | ||
@@ -1072,14 +1157,30 @@ static int spufs_psmap_open(struct inode *inode, struct file *file) | |||
1072 | struct spufs_inode_info *i = SPUFS_I(inode); | 1157 | struct spufs_inode_info *i = SPUFS_I(inode); |
1073 | struct spu_context *ctx = i->i_ctx; | 1158 | struct spu_context *ctx = i->i_ctx; |
1074 | 1159 | ||
1160 | spin_lock(&ctx->mapping_lock); | ||
1075 | file->private_data = i->i_ctx; | 1161 | file->private_data = i->i_ctx; |
1076 | ctx->psmap = inode->i_mapping; | 1162 | if (!i->i_openers++) |
1077 | smp_wmb(); | 1163 | ctx->psmap = inode->i_mapping; |
1164 | spin_unlock(&ctx->mapping_lock); | ||
1078 | return nonseekable_open(inode, file); | 1165 | return nonseekable_open(inode, file); |
1079 | } | 1166 | } |
1080 | 1167 | ||
1168 | static int | ||
1169 | spufs_psmap_release(struct inode *inode, struct file *file) | ||
1170 | { | ||
1171 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
1172 | struct spu_context *ctx = i->i_ctx; | ||
1173 | |||
1174 | spin_lock(&ctx->mapping_lock); | ||
1175 | if (!--i->i_openers) | ||
1176 | ctx->psmap = NULL; | ||
1177 | spin_unlock(&ctx->mapping_lock); | ||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1081 | static const struct file_operations spufs_psmap_fops = { | 1181 | static const struct file_operations spufs_psmap_fops = { |
1082 | .open = spufs_psmap_open, | 1182 | .open = spufs_psmap_open, |
1183 | .release = spufs_psmap_release, | ||
1083 | .mmap = spufs_psmap_mmap, | 1184 | .mmap = spufs_psmap_mmap, |
1084 | }; | 1185 | }; |
1085 | 1186 | ||
@@ -1126,12 +1227,27 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) | |||
1126 | if (atomic_read(&inode->i_count) != 1) | 1227 | if (atomic_read(&inode->i_count) != 1) |
1127 | return -EBUSY; | 1228 | return -EBUSY; |
1128 | 1229 | ||
1230 | spin_lock(&ctx->mapping_lock); | ||
1129 | file->private_data = ctx; | 1231 | file->private_data = ctx; |
1130 | ctx->mfc = inode->i_mapping; | 1232 | if (!i->i_openers++) |
1131 | smp_wmb(); | 1233 | ctx->mfc = inode->i_mapping; |
1234 | spin_unlock(&ctx->mapping_lock); | ||
1132 | return nonseekable_open(inode, file); | 1235 | return nonseekable_open(inode, file); |
1133 | } | 1236 | } |
1134 | 1237 | ||
1238 | static int | ||
1239 | spufs_mfc_release(struct inode *inode, struct file *file) | ||
1240 | { | ||
1241 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
1242 | struct spu_context *ctx = i->i_ctx; | ||
1243 | |||
1244 | spin_lock(&ctx->mapping_lock); | ||
1245 | if (!--i->i_openers) | ||
1246 | ctx->mfc = NULL; | ||
1247 | spin_unlock(&ctx->mapping_lock); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1135 | /* interrupt-level mfc callback function. */ | 1251 | /* interrupt-level mfc callback function. */ |
1136 | void spufs_mfc_callback(struct spu *spu) | 1252 | void spufs_mfc_callback(struct spu *spu) |
1137 | { | 1253 | { |
@@ -1313,7 +1429,10 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | |||
1313 | if (ret) | 1429 | if (ret) |
1314 | goto out; | 1430 | goto out; |
1315 | 1431 | ||
1316 | spu_acquire_runnable(ctx, 0); | 1432 | ret = spu_acquire_runnable(ctx, 0); |
1433 | if (ret) | ||
1434 | goto out; | ||
1435 | |||
1317 | if (file->f_flags & O_NONBLOCK) { | 1436 | if (file->f_flags & O_NONBLOCK) { |
1318 | ret = ctx->ops->send_mfc_command(ctx, &cmd); | 1437 | ret = ctx->ops->send_mfc_command(ctx, &cmd); |
1319 | } else { | 1438 | } else { |
@@ -1399,6 +1518,7 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on) | |||
1399 | 1518 | ||
1400 | static const struct file_operations spufs_mfc_fops = { | 1519 | static const struct file_operations spufs_mfc_fops = { |
1401 | .open = spufs_mfc_open, | 1520 | .open = spufs_mfc_open, |
1521 | .release = spufs_mfc_release, | ||
1402 | .read = spufs_mfc_read, | 1522 | .read = spufs_mfc_read, |
1403 | .write = spufs_mfc_write, | 1523 | .write = spufs_mfc_write, |
1404 | .poll = spufs_mfc_poll, | 1524 | .poll = spufs_mfc_poll, |
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index ae42e03b8c86..428875c5e4ec 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c | |||
@@ -296,6 +296,14 @@ static int spu_hw_send_mfc_command(struct spu_context *ctx, | |||
296 | } | 296 | } |
297 | } | 297 | } |
298 | 298 | ||
299 | static void spu_hw_restart_dma(struct spu_context *ctx) | ||
300 | { | ||
301 | struct spu_priv2 __iomem *priv2 = ctx->spu->priv2; | ||
302 | |||
303 | if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags)) | ||
304 | out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); | ||
305 | } | ||
306 | |||
299 | struct spu_context_ops spu_hw_ops = { | 307 | struct spu_context_ops spu_hw_ops = { |
300 | .mbox_read = spu_hw_mbox_read, | 308 | .mbox_read = spu_hw_mbox_read, |
301 | .mbox_stat_read = spu_hw_mbox_stat_read, | 309 | .mbox_stat_read = spu_hw_mbox_stat_read, |
@@ -320,4 +328,5 @@ struct spu_context_ops spu_hw_ops = { | |||
320 | .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus, | 328 | .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus, |
321 | .get_mfc_free_elements = spu_hw_get_mfc_free_elements, | 329 | .get_mfc_free_elements = spu_hw_get_mfc_free_elements, |
322 | .send_mfc_command = spu_hw_send_mfc_command, | 330 | .send_mfc_command = spu_hw_send_mfc_command, |
331 | .restart_dma = spu_hw_restart_dma, | ||
323 | }; | 332 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e3f4ee97c913..13e4f70ec8c0 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <asm/prom.h> | 36 | #include <asm/prom.h> |
37 | #include <asm/semaphore.h> | 37 | #include <asm/semaphore.h> |
38 | #include <asm/spu.h> | 38 | #include <asm/spu.h> |
39 | #include <asm/spu_priv1.h> | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
41 | #include "spufs.h" | 42 | #include "spufs.h" |
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb) | |||
54 | 55 | ||
55 | ei->i_gang = NULL; | 56 | ei->i_gang = NULL; |
56 | ei->i_ctx = NULL; | 57 | ei->i_ctx = NULL; |
58 | ei->i_openers = 0; | ||
57 | 59 | ||
58 | return &ei->vfs_inode; | 60 | return &ei->vfs_inode; |
59 | } | 61 | } |
@@ -520,13 +522,14 @@ out: | |||
520 | 522 | ||
521 | /* File system initialization */ | 523 | /* File system initialization */ |
522 | enum { | 524 | enum { |
523 | Opt_uid, Opt_gid, Opt_err, | 525 | Opt_uid, Opt_gid, Opt_mode, Opt_err, |
524 | }; | 526 | }; |
525 | 527 | ||
526 | static match_table_t spufs_tokens = { | 528 | static match_table_t spufs_tokens = { |
527 | { Opt_uid, "uid=%d" }, | 529 | { Opt_uid, "uid=%d" }, |
528 | { Opt_gid, "gid=%d" }, | 530 | { Opt_gid, "gid=%d" }, |
529 | { Opt_err, NULL }, | 531 | { Opt_mode, "mode=%o" }, |
532 | { Opt_err, NULL }, | ||
530 | }; | 533 | }; |
531 | 534 | ||
532 | static int | 535 | static int |
@@ -553,6 +556,11 @@ spufs_parse_options(char *options, struct inode *root) | |||
553 | return 0; | 556 | return 0; |
554 | root->i_gid = option; | 557 | root->i_gid = option; |
555 | break; | 558 | break; |
559 | case Opt_mode: | ||
560 | if (match_octal(&args[0], &option)) | ||
561 | return 0; | ||
562 | root->i_mode = option | S_IFDIR; | ||
563 | break; | ||
556 | default: | 564 | default: |
557 | return 0; | 565 | return 0; |
558 | } | 566 | } |
@@ -560,6 +568,11 @@ spufs_parse_options(char *options, struct inode *root) | |||
560 | return 1; | 568 | return 1; |
561 | } | 569 | } |
562 | 570 | ||
571 | static void spufs_exit_isolated_loader(void) | ||
572 | { | ||
573 | kfree(isolated_loader); | ||
574 | } | ||
575 | |||
563 | static void | 576 | static void |
564 | spufs_init_isolated_loader(void) | 577 | spufs_init_isolated_loader(void) |
565 | { | 578 | { |
@@ -653,6 +666,10 @@ static int __init spufs_init(void) | |||
653 | { | 666 | { |
654 | int ret; | 667 | int ret; |
655 | 668 | ||
669 | ret = -ENODEV; | ||
670 | if (!spu_management_ops) | ||
671 | goto out; | ||
672 | |||
656 | ret = -ENOMEM; | 673 | ret = -ENOMEM; |
657 | spufs_inode_cache = kmem_cache_create("spufs_inode_cache", | 674 | spufs_inode_cache = kmem_cache_create("spufs_inode_cache", |
658 | sizeof(struct spufs_inode_info), 0, | 675 | sizeof(struct spufs_inode_info), 0, |
@@ -660,25 +677,29 @@ static int __init spufs_init(void) | |||
660 | 677 | ||
661 | if (!spufs_inode_cache) | 678 | if (!spufs_inode_cache) |
662 | goto out; | 679 | goto out; |
663 | if (spu_sched_init() != 0) { | 680 | ret = spu_sched_init(); |
664 | kmem_cache_destroy(spufs_inode_cache); | ||
665 | goto out; | ||
666 | } | ||
667 | ret = register_filesystem(&spufs_type); | ||
668 | if (ret) | 681 | if (ret) |
669 | goto out_cache; | 682 | goto out_cache; |
683 | ret = register_filesystem(&spufs_type); | ||
684 | if (ret) | ||
685 | goto out_sched; | ||
670 | ret = register_spu_syscalls(&spufs_calls); | 686 | ret = register_spu_syscalls(&spufs_calls); |
671 | if (ret) | 687 | if (ret) |
672 | goto out_fs; | 688 | goto out_fs; |
673 | ret = register_arch_coredump_calls(&spufs_coredump_calls); | 689 | ret = register_arch_coredump_calls(&spufs_coredump_calls); |
674 | if (ret) | 690 | if (ret) |
675 | goto out_fs; | 691 | goto out_syscalls; |
676 | 692 | ||
677 | spufs_init_isolated_loader(); | 693 | spufs_init_isolated_loader(); |
678 | 694 | ||
679 | return 0; | 695 | return 0; |
696 | |||
697 | out_syscalls: | ||
698 | unregister_spu_syscalls(&spufs_calls); | ||
680 | out_fs: | 699 | out_fs: |
681 | unregister_filesystem(&spufs_type); | 700 | unregister_filesystem(&spufs_type); |
701 | out_sched: | ||
702 | spu_sched_exit(); | ||
682 | out_cache: | 703 | out_cache: |
683 | kmem_cache_destroy(spufs_inode_cache); | 704 | kmem_cache_destroy(spufs_inode_cache); |
684 | out: | 705 | out: |
@@ -689,6 +710,7 @@ module_init(spufs_init); | |||
689 | static void __exit spufs_exit(void) | 710 | static void __exit spufs_exit(void) |
690 | { | 711 | { |
691 | spu_sched_exit(); | 712 | spu_sched_exit(); |
713 | spufs_exit_isolated_loader(); | ||
692 | unregister_arch_coredump_calls(&spufs_coredump_calls); | 714 | unregister_arch_coredump_calls(&spufs_coredump_calls); |
693 | unregister_spu_syscalls(&spufs_calls); | 715 | unregister_spu_syscalls(&spufs_calls); |
694 | unregister_filesystem(&spufs_type); | 716 | unregister_filesystem(&spufs_type); |
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index f95a611ca362..57626600b1a4 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -18,27 +18,6 @@ void spufs_stop_callback(struct spu *spu) | |||
18 | wake_up_all(&ctx->stop_wq); | 18 | wake_up_all(&ctx->stop_wq); |
19 | } | 19 | } |
20 | 20 | ||
21 | void spufs_dma_callback(struct spu *spu, int type) | ||
22 | { | ||
23 | struct spu_context *ctx = spu->ctx; | ||
24 | |||
25 | if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { | ||
26 | ctx->event_return |= type; | ||
27 | wake_up_all(&ctx->stop_wq); | ||
28 | } else { | ||
29 | switch (type) { | ||
30 | case SPE_EVENT_DMA_ALIGNMENT: | ||
31 | case SPE_EVENT_SPE_DATA_STORAGE: | ||
32 | case SPE_EVENT_INVALID_DMA: | ||
33 | force_sig(SIGBUS, /* info, */ current); | ||
34 | break; | ||
35 | case SPE_EVENT_SPE_ERROR: | ||
36 | force_sig(SIGILL, /* info */ current); | ||
37 | break; | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static inline int spu_stopped(struct spu_context *ctx, u32 * stat) | 21 | static inline int spu_stopped(struct spu_context *ctx, u32 * stat) |
43 | { | 22 | { |
44 | struct spu *spu; | 23 | struct spu *spu; |
@@ -63,13 +42,18 @@ static int spu_setup_isolated(struct spu_context *ctx) | |||
63 | const u32 status_loading = SPU_STATUS_RUNNING | 42 | const u32 status_loading = SPU_STATUS_RUNNING |
64 | | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; | 43 | | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; |
65 | 44 | ||
45 | ret = -ENODEV; | ||
66 | if (!isolated_loader) | 46 | if (!isolated_loader) |
67 | return -ENODEV; | ||
68 | |||
69 | ret = spu_acquire_exclusive(ctx); | ||
70 | if (ret) | ||
71 | goto out; | 47 | goto out; |
72 | 48 | ||
49 | /* | ||
50 | * We need to exclude userspace access to the context. | ||
51 | * | ||
52 | * To protect against memory access we invalidate all ptes | ||
53 | * and make sure the pagefault handlers block on the mutex. | ||
54 | */ | ||
55 | spu_unmap_mappings(ctx); | ||
56 | |||
73 | mfc_cntl = &ctx->spu->priv2->mfc_control_RW; | 57 | mfc_cntl = &ctx->spu->priv2->mfc_control_RW; |
74 | 58 | ||
75 | /* purge the MFC DMA queue to ensure no spurious accesses before we | 59 | /* purge the MFC DMA queue to ensure no spurious accesses before we |
@@ -82,7 +66,7 @@ static int spu_setup_isolated(struct spu_context *ctx) | |||
82 | printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", | 66 | printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", |
83 | __FUNCTION__); | 67 | __FUNCTION__); |
84 | ret = -EIO; | 68 | ret = -EIO; |
85 | goto out_unlock; | 69 | goto out; |
86 | } | 70 | } |
87 | cond_resched(); | 71 | cond_resched(); |
88 | } | 72 | } |
@@ -119,12 +103,15 @@ static int spu_setup_isolated(struct spu_context *ctx) | |||
119 | pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); | 103 | pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); |
120 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | 104 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); |
121 | ret = -EACCES; | 105 | ret = -EACCES; |
106 | goto out_drop_priv; | ||
107 | } | ||
122 | 108 | ||
123 | } else if (!(status & SPU_STATUS_ISOLATED_STATE)) { | 109 | if (!(status & SPU_STATUS_ISOLATED_STATE)) { |
124 | /* This isn't allowed by the CBEA, but check anyway */ | 110 | /* This isn't allowed by the CBEA, but check anyway */ |
125 | pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); | 111 | pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); |
126 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); | 112 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); |
127 | ret = -EINVAL; | 113 | ret = -EINVAL; |
114 | goto out_drop_priv; | ||
128 | } | 115 | } |
129 | 116 | ||
130 | out_drop_priv: | 117 | out_drop_priv: |
@@ -132,30 +119,19 @@ out_drop_priv: | |||
132 | sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; | 119 | sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; |
133 | spu_mfc_sr1_set(ctx->spu, sr1); | 120 | spu_mfc_sr1_set(ctx->spu, sr1); |
134 | 121 | ||
135 | out_unlock: | ||
136 | spu_release(ctx); | ||
137 | out: | 122 | out: |
138 | return ret; | 123 | return ret; |
139 | } | 124 | } |
140 | 125 | ||
141 | static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | 126 | static int spu_run_init(struct spu_context *ctx, u32 * npc) |
142 | { | 127 | { |
143 | int ret; | ||
144 | unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; | ||
145 | |||
146 | ret = spu_acquire_runnable(ctx, 0); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | if (ctx->flags & SPU_CREATE_ISOLATE) { | 128 | if (ctx->flags & SPU_CREATE_ISOLATE) { |
129 | unsigned long runcntl; | ||
130 | |||
151 | if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { | 131 | if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { |
152 | /* Need to release ctx, because spu_setup_isolated will | 132 | int ret = spu_setup_isolated(ctx); |
153 | * acquire it exclusively. | 133 | if (ret) |
154 | */ | 134 | return ret; |
155 | spu_release(ctx); | ||
156 | ret = spu_setup_isolated(ctx); | ||
157 | if (!ret) | ||
158 | ret = spu_acquire_runnable(ctx, 0); | ||
159 | } | 135 | } |
160 | 136 | ||
161 | /* if userspace has set the runcntrl register (eg, to issue an | 137 | /* if userspace has set the runcntrl register (eg, to issue an |
@@ -164,16 +140,17 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | |||
164 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); | 140 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); |
165 | if (runcntl == 0) | 141 | if (runcntl == 0) |
166 | runcntl = SPU_RUNCNTL_RUNNABLE; | 142 | runcntl = SPU_RUNCNTL_RUNNABLE; |
143 | ctx->ops->runcntl_write(ctx, runcntl); | ||
167 | } else { | 144 | } else { |
168 | spu_start_tick(ctx); | 145 | spu_start_tick(ctx); |
169 | ctx->ops->npc_write(ctx, *npc); | 146 | ctx->ops->npc_write(ctx, *npc); |
147 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | ||
170 | } | 148 | } |
171 | 149 | ||
172 | ctx->ops->runcntl_write(ctx, runcntl); | 150 | return 0; |
173 | return ret; | ||
174 | } | 151 | } |
175 | 152 | ||
176 | static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, | 153 | static int spu_run_fini(struct spu_context *ctx, u32 * npc, |
177 | u32 * status) | 154 | u32 * status) |
178 | { | 155 | { |
179 | int ret = 0; | 156 | int ret = 0; |
@@ -189,19 +166,27 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, | |||
189 | return ret; | 166 | return ret; |
190 | } | 167 | } |
191 | 168 | ||
192 | static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, | 169 | static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, |
193 | u32 *status) | 170 | u32 *status) |
194 | { | 171 | { |
195 | int ret; | 172 | int ret; |
196 | 173 | ||
197 | if ((ret = spu_run_fini(ctx, npc, status)) != 0) | 174 | ret = spu_run_fini(ctx, npc, status); |
175 | if (ret) | ||
198 | return ret; | 176 | return ret; |
199 | if (*status & (SPU_STATUS_STOPPED_BY_STOP | | 177 | |
200 | SPU_STATUS_STOPPED_BY_HALT)) { | 178 | if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT)) |
201 | return *status; | 179 | return *status; |
202 | } | 180 | |
203 | if ((ret = spu_run_init(ctx, npc)) != 0) | 181 | ret = spu_acquire_runnable(ctx, 0); |
182 | if (ret) | ||
183 | return ret; | ||
184 | |||
185 | ret = spu_run_init(ctx, npc); | ||
186 | if (ret) { | ||
187 | spu_release(ctx); | ||
204 | return ret; | 188 | return ret; |
189 | } | ||
205 | return 0; | 190 | return 0; |
206 | } | 191 | } |
207 | 192 | ||
@@ -253,17 +238,17 @@ int spu_process_callback(struct spu_context *ctx) | |||
253 | { | 238 | { |
254 | struct spu_syscall_block s; | 239 | struct spu_syscall_block s; |
255 | u32 ls_pointer, npc; | 240 | u32 ls_pointer, npc; |
256 | char *ls; | 241 | void __iomem *ls; |
257 | long spu_ret; | 242 | long spu_ret; |
258 | int ret; | 243 | int ret; |
259 | 244 | ||
260 | /* get syscall block from local store */ | 245 | /* get syscall block from local store */ |
261 | npc = ctx->ops->npc_read(ctx); | 246 | npc = ctx->ops->npc_read(ctx) & ~3; |
262 | ls = ctx->ops->get_ls(ctx); | 247 | ls = (void __iomem *)ctx->ops->get_ls(ctx); |
263 | ls_pointer = *(u32*)(ls + npc); | 248 | ls_pointer = in_be32(ls + npc); |
264 | if (ls_pointer > (LS_SIZE - sizeof(s))) | 249 | if (ls_pointer > (LS_SIZE - sizeof(s))) |
265 | return -EFAULT; | 250 | return -EFAULT; |
266 | memcpy(&s, ls + ls_pointer, sizeof (s)); | 251 | memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); |
267 | 252 | ||
268 | /* do actual syscall without pinning the spu */ | 253 | /* do actual syscall without pinning the spu */ |
269 | ret = 0; | 254 | ret = 0; |
@@ -283,7 +268,7 @@ int spu_process_callback(struct spu_context *ctx) | |||
283 | } | 268 | } |
284 | 269 | ||
285 | /* write result, jump over indirect pointer */ | 270 | /* write result, jump over indirect pointer */ |
286 | memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret)); | 271 | memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); |
287 | ctx->ops->npc_write(ctx, npc); | 272 | ctx->ops->npc_write(ctx, npc); |
288 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | 273 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); |
289 | return ret; | 274 | return ret; |
@@ -292,11 +277,8 @@ int spu_process_callback(struct spu_context *ctx) | |||
292 | static inline int spu_process_events(struct spu_context *ctx) | 277 | static inline int spu_process_events(struct spu_context *ctx) |
293 | { | 278 | { |
294 | struct spu *spu = ctx->spu; | 279 | struct spu *spu = ctx->spu; |
295 | u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; | ||
296 | int ret = 0; | 280 | int ret = 0; |
297 | 281 | ||
298 | if (spu->dsisr & pte_fault) | ||
299 | ret = spu_irq_class_1_bottom(spu); | ||
300 | if (spu->class_0_pending) | 282 | if (spu->class_0_pending) |
301 | ret = spu_irq_class_0_bottom(spu); | 283 | ret = spu_irq_class_0_bottom(spu); |
302 | if (!ret && signal_pending(current)) | 284 | if (!ret && signal_pending(current)) |
@@ -310,14 +292,21 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, | |||
310 | int ret; | 292 | int ret; |
311 | u32 status; | 293 | u32 status; |
312 | 294 | ||
313 | if (down_interruptible(&ctx->run_sema)) | 295 | if (mutex_lock_interruptible(&ctx->run_mutex)) |
314 | return -ERESTARTSYS; | 296 | return -ERESTARTSYS; |
315 | 297 | ||
316 | ctx->ops->master_start(ctx); | 298 | ctx->ops->master_start(ctx); |
317 | ctx->event_return = 0; | 299 | ctx->event_return = 0; |
318 | ret = spu_run_init(ctx, npc); | 300 | |
301 | ret = spu_acquire_runnable(ctx, 0); | ||
319 | if (ret) | 302 | if (ret) |
303 | return ret; | ||
304 | |||
305 | ret = spu_run_init(ctx, npc); | ||
306 | if (ret) { | ||
307 | spu_release(ctx); | ||
320 | goto out; | 308 | goto out; |
309 | } | ||
321 | 310 | ||
322 | do { | 311 | do { |
323 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); | 312 | ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); |
@@ -330,6 +319,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, | |||
330 | break; | 319 | break; |
331 | status &= ~SPU_STATUS_STOPPED_BY_STOP; | 320 | status &= ~SPU_STATUS_STOPPED_BY_STOP; |
332 | } | 321 | } |
322 | ret = spufs_handle_class1(ctx); | ||
323 | if (ret) | ||
324 | break; | ||
325 | |||
333 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | 326 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { |
334 | ret = spu_reacquire_runnable(ctx, npc, &status); | 327 | ret = spu_reacquire_runnable(ctx, npc, &status); |
335 | if (ret) { | 328 | if (ret) { |
@@ -363,6 +356,6 @@ out2: | |||
363 | 356 | ||
364 | out: | 357 | out: |
365 | *event = ctx->event_return; | 358 | *event = ctx->event_return; |
366 | up(&ctx->run_sema); | 359 | mutex_unlock(&ctx->run_mutex); |
367 | return ret; | 360 | return ret; |
368 | } | 361 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index c9561582ce2a..91030b8abdca 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -71,14 +71,27 @@ static inline int node_allowed(int node) | |||
71 | 71 | ||
72 | void spu_start_tick(struct spu_context *ctx) | 72 | void spu_start_tick(struct spu_context *ctx) |
73 | { | 73 | { |
74 | if (ctx->policy == SCHED_RR) | 74 | if (ctx->policy == SCHED_RR) { |
75 | /* | ||
76 | * Make sure the exiting bit is cleared. | ||
77 | */ | ||
78 | clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags); | ||
79 | mb(); | ||
75 | queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); | 80 | queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); |
81 | } | ||
76 | } | 82 | } |
77 | 83 | ||
78 | void spu_stop_tick(struct spu_context *ctx) | 84 | void spu_stop_tick(struct spu_context *ctx) |
79 | { | 85 | { |
80 | if (ctx->policy == SCHED_RR) | 86 | if (ctx->policy == SCHED_RR) { |
87 | /* | ||
88 | * While the work can be rearming normally setting this flag | ||
89 | * makes sure it does not rearm itself anymore. | ||
90 | */ | ||
91 | set_bit(SPU_SCHED_EXITING, &ctx->sched_flags); | ||
92 | mb(); | ||
81 | cancel_delayed_work(&ctx->sched_work); | 93 | cancel_delayed_work(&ctx->sched_work); |
94 | } | ||
82 | } | 95 | } |
83 | 96 | ||
84 | void spu_sched_tick(struct work_struct *work) | 97 | void spu_sched_tick(struct work_struct *work) |
@@ -86,7 +99,15 @@ void spu_sched_tick(struct work_struct *work) | |||
86 | struct spu_context *ctx = | 99 | struct spu_context *ctx = |
87 | container_of(work, struct spu_context, sched_work.work); | 100 | container_of(work, struct spu_context, sched_work.work); |
88 | struct spu *spu; | 101 | struct spu *spu; |
89 | int rearm = 1; | 102 | int preempted = 0; |
103 | |||
104 | /* | ||
105 | * If this context is being stopped avoid rescheduling from the | ||
106 | * scheduler tick because we would block on the state_mutex. | ||
107 | * The caller will yield the spu later on anyway. | ||
108 | */ | ||
109 | if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) | ||
110 | return; | ||
90 | 111 | ||
91 | mutex_lock(&ctx->state_mutex); | 112 | mutex_lock(&ctx->state_mutex); |
92 | spu = ctx->spu; | 113 | spu = ctx->spu; |
@@ -94,12 +115,19 @@ void spu_sched_tick(struct work_struct *work) | |||
94 | int best = sched_find_first_bit(spu_prio->bitmap); | 115 | int best = sched_find_first_bit(spu_prio->bitmap); |
95 | if (best <= ctx->prio) { | 116 | if (best <= ctx->prio) { |
96 | spu_deactivate(ctx); | 117 | spu_deactivate(ctx); |
97 | rearm = 0; | 118 | preempted = 1; |
98 | } | 119 | } |
99 | } | 120 | } |
100 | mutex_unlock(&ctx->state_mutex); | 121 | mutex_unlock(&ctx->state_mutex); |
101 | 122 | ||
102 | if (rearm) | 123 | if (preempted) { |
124 | /* | ||
125 | * We need to break out of the wait loop in spu_run manually | ||
126 | * to ensure this context gets put on the runqueue again | ||
127 | * ASAP. | ||
128 | */ | ||
129 | wake_up(&ctx->stop_wq); | ||
130 | } else | ||
103 | spu_start_tick(ctx); | 131 | spu_start_tick(ctx); |
104 | } | 132 | } |
105 | 133 | ||
@@ -208,58 +236,40 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
208 | * spu_add_to_rq - add a context to the runqueue | 236 | * spu_add_to_rq - add a context to the runqueue |
209 | * @ctx: context to add | 237 | * @ctx: context to add |
210 | */ | 238 | */ |
211 | static void spu_add_to_rq(struct spu_context *ctx) | 239 | static void __spu_add_to_rq(struct spu_context *ctx) |
212 | { | 240 | { |
213 | spin_lock(&spu_prio->runq_lock); | 241 | int prio = ctx->prio; |
214 | list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); | ||
215 | set_bit(ctx->prio, spu_prio->bitmap); | ||
216 | spin_unlock(&spu_prio->runq_lock); | ||
217 | } | ||
218 | 242 | ||
219 | /** | 243 | list_add_tail(&ctx->rq, &spu_prio->runq[prio]); |
220 | * spu_del_from_rq - remove a context from the runqueue | 244 | set_bit(prio, spu_prio->bitmap); |
221 | * @ctx: context to remove | ||
222 | */ | ||
223 | static void spu_del_from_rq(struct spu_context *ctx) | ||
224 | { | ||
225 | spin_lock(&spu_prio->runq_lock); | ||
226 | list_del_init(&ctx->rq); | ||
227 | if (list_empty(&spu_prio->runq[ctx->prio])) | ||
228 | clear_bit(ctx->prio, spu_prio->bitmap); | ||
229 | spin_unlock(&spu_prio->runq_lock); | ||
230 | } | 245 | } |
231 | 246 | ||
232 | /** | 247 | static void __spu_del_from_rq(struct spu_context *ctx) |
233 | * spu_grab_context - remove one context from the runqueue | ||
234 | * @prio: priority of the context to be removed | ||
235 | * | ||
236 | * This function removes one context from the runqueue for priority @prio. | ||
237 | * If there is more than one context with the given priority the first | ||
238 | * task on the runqueue will be taken. | ||
239 | * | ||
240 | * Returns the spu_context it just removed. | ||
241 | * | ||
242 | * Must be called with spu_prio->runq_lock held. | ||
243 | */ | ||
244 | static struct spu_context *spu_grab_context(int prio) | ||
245 | { | 248 | { |
246 | struct list_head *rq = &spu_prio->runq[prio]; | 249 | int prio = ctx->prio; |
247 | 250 | ||
248 | if (list_empty(rq)) | 251 | if (!list_empty(&ctx->rq)) |
249 | return NULL; | 252 | list_del_init(&ctx->rq); |
250 | return list_entry(rq->next, struct spu_context, rq); | 253 | if (list_empty(&spu_prio->runq[prio])) |
254 | clear_bit(prio, spu_prio->bitmap); | ||
251 | } | 255 | } |
252 | 256 | ||
253 | static void spu_prio_wait(struct spu_context *ctx) | 257 | static void spu_prio_wait(struct spu_context *ctx) |
254 | { | 258 | { |
255 | DEFINE_WAIT(wait); | 259 | DEFINE_WAIT(wait); |
256 | 260 | ||
261 | spin_lock(&spu_prio->runq_lock); | ||
257 | prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); | 262 | prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); |
258 | if (!signal_pending(current)) { | 263 | if (!signal_pending(current)) { |
264 | __spu_add_to_rq(ctx); | ||
265 | spin_unlock(&spu_prio->runq_lock); | ||
259 | mutex_unlock(&ctx->state_mutex); | 266 | mutex_unlock(&ctx->state_mutex); |
260 | schedule(); | 267 | schedule(); |
261 | mutex_lock(&ctx->state_mutex); | 268 | mutex_lock(&ctx->state_mutex); |
269 | spin_lock(&spu_prio->runq_lock); | ||
270 | __spu_del_from_rq(ctx); | ||
262 | } | 271 | } |
272 | spin_unlock(&spu_prio->runq_lock); | ||
263 | __set_current_state(TASK_RUNNING); | 273 | __set_current_state(TASK_RUNNING); |
264 | remove_wait_queue(&ctx->stop_wq, &wait); | 274 | remove_wait_queue(&ctx->stop_wq, &wait); |
265 | } | 275 | } |
@@ -280,9 +290,14 @@ static void spu_reschedule(struct spu *spu) | |||
280 | spin_lock(&spu_prio->runq_lock); | 290 | spin_lock(&spu_prio->runq_lock); |
281 | best = sched_find_first_bit(spu_prio->bitmap); | 291 | best = sched_find_first_bit(spu_prio->bitmap); |
282 | if (best < MAX_PRIO) { | 292 | if (best < MAX_PRIO) { |
283 | struct spu_context *ctx = spu_grab_context(best); | 293 | struct list_head *rq = &spu_prio->runq[best]; |
284 | if (ctx) | 294 | struct spu_context *ctx; |
285 | wake_up(&ctx->stop_wq); | 295 | |
296 | BUG_ON(list_empty(rq)); | ||
297 | |||
298 | ctx = list_entry(rq->next, struct spu_context, rq); | ||
299 | __spu_del_from_rq(ctx); | ||
300 | wake_up(&ctx->stop_wq); | ||
286 | } | 301 | } |
287 | spin_unlock(&spu_prio->runq_lock); | 302 | spin_unlock(&spu_prio->runq_lock); |
288 | } | 303 | } |
@@ -365,6 +380,12 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
365 | } | 380 | } |
366 | spu_unbind_context(spu, victim); | 381 | spu_unbind_context(spu, victim); |
367 | mutex_unlock(&victim->state_mutex); | 382 | mutex_unlock(&victim->state_mutex); |
383 | /* | ||
384 | * We need to break out of the wait loop in spu_run | ||
385 | * manually to ensure this context gets put on the | ||
386 | * runqueue again ASAP. | ||
387 | */ | ||
388 | wake_up(&victim->stop_wq); | ||
368 | return spu; | 389 | return spu; |
369 | } | 390 | } |
370 | } | 391 | } |
@@ -377,7 +398,7 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
377 | * @ctx: spu context to schedule | 398 | * @ctx: spu context to schedule |
378 | * @flags: flags (currently ignored) | 399 | * @flags: flags (currently ignored) |
379 | * | 400 | * |
380 | * Tries to find a free spu to run @ctx. If no free spu is availble | 401 | * Tries to find a free spu to run @ctx. If no free spu is available |
381 | * add the context to the runqueue so it gets woken up once an spu | 402 | * add the context to the runqueue so it gets woken up once an spu |
382 | * is available. | 403 | * is available. |
383 | */ | 404 | */ |
@@ -402,9 +423,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) | |||
402 | return 0; | 423 | return 0; |
403 | } | 424 | } |
404 | 425 | ||
405 | spu_add_to_rq(ctx); | ||
406 | spu_prio_wait(ctx); | 426 | spu_prio_wait(ctx); |
407 | spu_del_from_rq(ctx); | ||
408 | } while (!signal_pending(current)); | 427 | } while (!signal_pending(current)); |
409 | 428 | ||
410 | return -ERESTARTSYS; | 429 | return -ERESTARTSYS; |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 5c4e47d69d79..0a947fd7de57 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -41,7 +41,7 @@ struct spu_gang; | |||
41 | 41 | ||
42 | /* ctx->sched_flags */ | 42 | /* ctx->sched_flags */ |
43 | enum { | 43 | enum { |
44 | SPU_SCHED_WAKE = 0, /* currently unused */ | 44 | SPU_SCHED_EXITING = 0, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct spu_context { | 47 | struct spu_context { |
@@ -50,16 +50,17 @@ struct spu_context { | |||
50 | spinlock_t mmio_lock; /* protects mmio access */ | 50 | spinlock_t mmio_lock; /* protects mmio access */ |
51 | struct address_space *local_store; /* local store mapping. */ | 51 | struct address_space *local_store; /* local store mapping. */ |
52 | struct address_space *mfc; /* 'mfc' area mappings. */ | 52 | struct address_space *mfc; /* 'mfc' area mappings. */ |
53 | struct address_space *cntl; /* 'control' area mappings. */ | 53 | struct address_space *cntl; /* 'control' area mappings. */ |
54 | struct address_space *signal1; /* 'signal1' area mappings. */ | 54 | struct address_space *signal1; /* 'signal1' area mappings. */ |
55 | struct address_space *signal2; /* 'signal2' area mappings. */ | 55 | struct address_space *signal2; /* 'signal2' area mappings. */ |
56 | struct address_space *mss; /* 'mss' area mappings. */ | 56 | struct address_space *mss; /* 'mss' area mappings. */ |
57 | struct address_space *psmap; /* 'psmap' area mappings. */ | 57 | struct address_space *psmap; /* 'psmap' area mappings. */ |
58 | spinlock_t mapping_lock; | ||
58 | u64 object_id; /* user space pointer for oprofile */ | 59 | u64 object_id; /* user space pointer for oprofile */ |
59 | 60 | ||
60 | enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; | 61 | enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; |
61 | struct mutex state_mutex; | 62 | struct mutex state_mutex; |
62 | struct semaphore run_sema; | 63 | struct mutex run_mutex; |
63 | 64 | ||
64 | struct mm_struct *owner; | 65 | struct mm_struct *owner; |
65 | 66 | ||
@@ -140,6 +141,7 @@ struct spu_context_ops { | |||
140 | struct spu_dma_info * info); | 141 | struct spu_dma_info * info); |
141 | void (*proxydma_info_read) (struct spu_context * ctx, | 142 | void (*proxydma_info_read) (struct spu_context * ctx, |
142 | struct spu_proxydma_info * info); | 143 | struct spu_proxydma_info * info); |
144 | void (*restart_dma)(struct spu_context *ctx); | ||
143 | }; | 145 | }; |
144 | 146 | ||
145 | extern struct spu_context_ops spu_hw_ops; | 147 | extern struct spu_context_ops spu_hw_ops; |
@@ -149,6 +151,7 @@ struct spufs_inode_info { | |||
149 | struct spu_context *i_ctx; | 151 | struct spu_context *i_ctx; |
150 | struct spu_gang *i_gang; | 152 | struct spu_gang *i_gang; |
151 | struct inode vfs_inode; | 153 | struct inode vfs_inode; |
154 | int i_openers; | ||
152 | }; | 155 | }; |
153 | #define SPUFS_I(inode) \ | 156 | #define SPUFS_I(inode) \ |
154 | container_of(inode, struct spufs_inode_info, vfs_inode) | 157 | container_of(inode, struct spufs_inode_info, vfs_inode) |
@@ -170,6 +173,9 @@ int put_spu_gang(struct spu_gang *gang); | |||
170 | void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); | 173 | void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); |
171 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | 174 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); |
172 | 175 | ||
176 | /* fault handling */ | ||
177 | int spufs_handle_class1(struct spu_context *ctx); | ||
178 | |||
173 | /* context management */ | 179 | /* context management */ |
174 | static inline void spu_acquire(struct spu_context *ctx) | 180 | static inline void spu_acquire(struct spu_context *ctx) |
175 | { | 181 | { |
@@ -190,7 +196,6 @@ void spu_unmap_mappings(struct spu_context *ctx); | |||
190 | void spu_forget(struct spu_context *ctx); | 196 | void spu_forget(struct spu_context *ctx); |
191 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); | 197 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); |
192 | void spu_acquire_saved(struct spu_context *ctx); | 198 | void spu_acquire_saved(struct spu_context *ctx); |
193 | int spu_acquire_exclusive(struct spu_context *ctx); | ||
194 | 199 | ||
195 | int spu_activate(struct spu_context *ctx, unsigned long flags); | 200 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
196 | void spu_deactivate(struct spu_context *ctx); | 201 | void spu_deactivate(struct spu_context *ctx); |
@@ -218,14 +223,13 @@ extern char *isolated_loader; | |||
218 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | 223 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ |
219 | if (condition) \ | 224 | if (condition) \ |
220 | break; \ | 225 | break; \ |
221 | if (!signal_pending(current)) { \ | 226 | if (signal_pending(current)) { \ |
222 | spu_release(ctx); \ | 227 | __ret = -ERESTARTSYS; \ |
223 | schedule(); \ | 228 | break; \ |
224 | spu_acquire(ctx); \ | ||
225 | continue; \ | ||
226 | } \ | 229 | } \ |
227 | __ret = -ERESTARTSYS; \ | 230 | spu_release(ctx); \ |
228 | break; \ | 231 | schedule(); \ |
232 | spu_acquire(ctx); \ | ||
229 | } \ | 233 | } \ |
230 | finish_wait(&(wq), &__wait); \ | 234 | finish_wait(&(wq), &__wait); \ |
231 | __ret; \ | 235 | __ret; \ |
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index fd91c73de34e..8347c4a3f894 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c | |||
@@ -2084,6 +2084,10 @@ int spu_save(struct spu_state *prev, struct spu *spu) | |||
2084 | int rc; | 2084 | int rc; |
2085 | 2085 | ||
2086 | acquire_spu_lock(spu); /* Step 1. */ | 2086 | acquire_spu_lock(spu); /* Step 1. */ |
2087 | prev->dar = spu->dar; | ||
2088 | prev->dsisr = spu->dsisr; | ||
2089 | spu->dar = 0; | ||
2090 | spu->dsisr = 0; | ||
2087 | rc = __do_spu_save(prev, spu); /* Steps 2-53. */ | 2091 | rc = __do_spu_save(prev, spu); /* Steps 2-53. */ |
2088 | release_spu_lock(spu); | 2092 | release_spu_lock(spu); |
2089 | if (rc != 0 && rc != 2 && rc != 6) { | 2093 | if (rc != 0 && rc != 2 && rc != 6) { |
@@ -2109,9 +2113,9 @@ int spu_restore(struct spu_state *new, struct spu *spu) | |||
2109 | 2113 | ||
2110 | acquire_spu_lock(spu); | 2114 | acquire_spu_lock(spu); |
2111 | harvest(NULL, spu); | 2115 | harvest(NULL, spu); |
2112 | spu->dar = 0; | ||
2113 | spu->dsisr = 0; | ||
2114 | spu->slb_replace = 0; | 2116 | spu->slb_replace = 0; |
2117 | new->dar = 0; | ||
2118 | new->dsisr = 0; | ||
2115 | spu->class_0_pending = 0; | 2119 | spu->class_0_pending = 0; |
2116 | rc = __do_spu_restore(new, spu); | 2120 | rc = __do_spu_restore(new, spu); |
2117 | release_spu_lock(spu); | 2121 | release_spu_lock(spu); |