diff options
Diffstat (limited to 'arch/powerpc/platforms/cell/spu_base.c')
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 161 |
1 files changed, 17 insertions, 144 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); |