diff options
| -rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 7 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/backing_ops.c | 47 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/context.c | 5 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 294 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/hw_ops.c | 57 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/sched.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 20 | ||||
| -rw-r--r-- | arch/powerpc/platforms/cell/spufs/switch.c | 3 | ||||
| -rw-r--r-- | include/asm-powerpc/spu.h | 1 |
9 files changed, 431 insertions, 5 deletions
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index a8fa1eeeb174..162b6cfa8a43 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
| @@ -111,7 +111,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
| 111 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX | 111 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX |
| 112 | static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) | 112 | static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) |
| 113 | { | 113 | { |
| 114 | pr_debug("%s\n", __FUNCTION__); | 114 | pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea); |
| 115 | 115 | ||
| 116 | /* Handle kernel space hash faults immediately. | 116 | /* Handle kernel space hash faults immediately. |
| 117 | User hash faults need to be deferred to process context. */ | 117 | User hash faults need to be deferred to process context. */ |
| @@ -168,7 +168,7 @@ static int __spu_trap_halt(struct spu *spu) | |||
| 168 | static int __spu_trap_tag_group(struct spu *spu) | 168 | static int __spu_trap_tag_group(struct spu *spu) |
| 169 | { | 169 | { |
| 170 | pr_debug("%s\n", __FUNCTION__); | 170 | pr_debug("%s\n", __FUNCTION__); |
| 171 | /* wake_up(&spu->dma_wq); */ | 171 | spu->mfc_callback(spu); |
| 172 | return 0; | 172 | return 0; |
| 173 | } | 173 | } |
| 174 | 174 | ||
| @@ -242,6 +242,8 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) | |||
| 242 | spu_mfc_dsisr_set(spu, 0ul); | 242 | spu_mfc_dsisr_set(spu, 0ul); |
| 243 | spu_int_stat_clear(spu, 1, stat); | 243 | spu_int_stat_clear(spu, 1, stat); |
| 244 | spin_unlock(&spu->register_lock); | 244 | spin_unlock(&spu->register_lock); |
| 245 | pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat, | ||
| 246 | dar, dsisr); | ||
| 245 | 247 | ||
| 246 | if (stat & 1) /* segment fault */ | 248 | if (stat & 1) /* segment fault */ |
| 247 | __spu_trap_data_seg(spu, dar); | 249 | __spu_trap_data_seg(spu, dar); |
| @@ -632,6 +634,7 @@ static int __init create_spu(struct device_node *spe) | |||
| 632 | spu->ibox_callback = NULL; | 634 | spu->ibox_callback = NULL; |
| 633 | spu->wbox_callback = NULL; | 635 | spu->wbox_callback = NULL; |
| 634 | spu->stop_callback = NULL; | 636 | spu->stop_callback = NULL; |
| 637 | spu->mfc_callback = NULL; | ||
| 635 | 638 | ||
| 636 | mutex_lock(&spu_mutex); | 639 | mutex_lock(&spu_mutex); |
| 637 | spu->number = number++; | 640 | spu->number = number++; |
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index a5c489a53c61..f1d35ddc9df3 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c | |||
| @@ -285,6 +285,49 @@ static void spu_backing_runcntl_stop(struct spu_context *ctx) | |||
| 285 | spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); | 285 | spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask, | ||
| 289 | u32 mode) | ||
| 290 | { | ||
| 291 | struct spu_problem_collapsed *prob = &ctx->csa.prob; | ||
| 292 | int ret; | ||
| 293 | |||
| 294 | spin_lock(&ctx->csa.register_lock); | ||
| 295 | ret = -EAGAIN; | ||
| 296 | if (prob->dma_querytype_RW) | ||
| 297 | goto out; | ||
| 298 | ret = 0; | ||
| 299 | /* FIXME: what are the side-effects of this? */ | ||
| 300 | prob->dma_querymask_RW = mask; | ||
| 301 | prob->dma_querytype_RW = mode; | ||
| 302 | out: | ||
| 303 | spin_unlock(&ctx->csa.register_lock); | ||
| 304 | |||
| 305 | return ret; | ||
| 306 | } | ||
| 307 | |||
| 308 | static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx) | ||
| 309 | { | ||
| 310 | return ctx->csa.prob.dma_tagstatus_R; | ||
| 311 | } | ||
| 312 | |||
| 313 | static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx) | ||
| 314 | { | ||
| 315 | return ctx->csa.prob.dma_qstatus_R; | ||
| 316 | } | ||
| 317 | |||
| 318 | static int spu_backing_send_mfc_command(struct spu_context *ctx, | ||
| 319 | struct mfc_dma_command *cmd) | ||
| 320 | { | ||
| 321 | int ret; | ||
| 322 | |||
| 323 | spin_lock(&ctx->csa.register_lock); | ||
| 324 | ret = -EAGAIN; | ||
| 325 | /* FIXME: set up priv2->puq */ | ||
| 326 | spin_unlock(&ctx->csa.register_lock); | ||
| 327 | |||
| 328 | return ret; | ||
| 329 | } | ||
| 330 | |||
| 288 | struct spu_context_ops spu_backing_ops = { | 331 | struct spu_context_ops spu_backing_ops = { |
| 289 | .mbox_read = spu_backing_mbox_read, | 332 | .mbox_read = spu_backing_mbox_read, |
| 290 | .mbox_stat_read = spu_backing_mbox_stat_read, | 333 | .mbox_stat_read = spu_backing_mbox_stat_read, |
| @@ -305,4 +348,8 @@ struct spu_context_ops spu_backing_ops = { | |||
| 305 | .get_ls = spu_backing_get_ls, | 348 | .get_ls = spu_backing_get_ls, |
| 306 | .runcntl_write = spu_backing_runcntl_write, | 349 | .runcntl_write = spu_backing_runcntl_write, |
| 307 | .runcntl_stop = spu_backing_runcntl_stop, | 350 | .runcntl_stop = spu_backing_runcntl_stop, |
| 351 | .set_mfc_query = spu_backing_set_mfc_query, | ||
| 352 | .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus, | ||
| 353 | .get_mfc_free_elements = spu_backing_get_mfc_free_elements, | ||
| 354 | .send_mfc_command = spu_backing_send_mfc_command, | ||
| 308 | }; | 355 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 336f238102fd..7e016b9eab21 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
| @@ -47,8 +47,11 @@ struct spu_context *alloc_spu_context(struct address_space *local_store) | |||
| 47 | init_waitqueue_head(&ctx->ibox_wq); | 47 | init_waitqueue_head(&ctx->ibox_wq); |
| 48 | init_waitqueue_head(&ctx->wbox_wq); | 48 | init_waitqueue_head(&ctx->wbox_wq); |
| 49 | init_waitqueue_head(&ctx->stop_wq); | 49 | init_waitqueue_head(&ctx->stop_wq); |
| 50 | init_waitqueue_head(&ctx->mfc_wq); | ||
| 50 | ctx->ibox_fasync = NULL; | 51 | ctx->ibox_fasync = NULL; |
| 51 | ctx->wbox_fasync = NULL; | 52 | ctx->wbox_fasync = NULL; |
| 53 | ctx->mfc_fasync = NULL; | ||
| 54 | ctx->tagwait = 0; | ||
| 52 | ctx->state = SPU_STATE_SAVED; | 55 | ctx->state = SPU_STATE_SAVED; |
| 53 | ctx->local_store = local_store; | 56 | ctx->local_store = local_store; |
| 54 | ctx->spu = NULL; | 57 | ctx->spu = NULL; |
| @@ -68,8 +71,6 @@ void destroy_spu_context(struct kref *kref) | |||
| 68 | ctx = container_of(kref, struct spu_context, kref); | 71 | ctx = container_of(kref, struct spu_context, kref); |
| 69 | down_write(&ctx->state_sema); | 72 | down_write(&ctx->state_sema); |
| 70 | spu_deactivate(ctx); | 73 | spu_deactivate(ctx); |
| 71 | ctx->ibox_fasync = NULL; | ||
| 72 | ctx->wbox_fasync = NULL; | ||
| 73 | up_write(&ctx->state_sema); | 74 | up_write(&ctx->state_sema); |
| 74 | spu_fini_csa(&ctx->csa); | 75 | spu_fini_csa(&ctx->csa); |
| 75 | kfree(ctx); | 76 | kfree(ctx); |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index dfa649c9b956..62fe9941ccee 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #undef DEBUG | ||
| 24 | |||
| 23 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
| 24 | #include <linux/ioctl.h> | 26 | #include <linux/ioctl.h> |
| 25 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| @@ -641,6 +643,297 @@ static u64 spufs_signal2_type_get(void *data) | |||
| 641 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, | 643 | DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, |
| 642 | spufs_signal2_type_set, "%llu"); | 644 | spufs_signal2_type_set, "%llu"); |
| 643 | 645 | ||
| 646 | |||
| 647 | static int spufs_mfc_open(struct inode *inode, struct file *file) | ||
| 648 | { | ||
| 649 | struct spufs_inode_info *i = SPUFS_I(inode); | ||
| 650 | struct spu_context *ctx = i->i_ctx; | ||
| 651 | |||
| 652 | /* we don't want to deal with DMA into other processes */ | ||
| 653 | if (ctx->owner != current->mm) | ||
| 654 | return -EINVAL; | ||
| 655 | |||
| 656 | if (atomic_read(&inode->i_count) != 1) | ||
| 657 | return -EBUSY; | ||
| 658 | |||
| 659 | file->private_data = ctx; | ||
| 660 | return nonseekable_open(inode, file); | ||
| 661 | } | ||
| 662 | |||
| 663 | /* interrupt-level mfc callback function. */ | ||
| 664 | void spufs_mfc_callback(struct spu *spu) | ||
| 665 | { | ||
| 666 | struct spu_context *ctx = spu->ctx; | ||
| 667 | |||
| 668 | wake_up_all(&ctx->mfc_wq); | ||
| 669 | |||
| 670 | pr_debug("%s %s\n", __FUNCTION__, spu->name); | ||
| 671 | if (ctx->mfc_fasync) { | ||
| 672 | u32 free_elements, tagstatus; | ||
| 673 | unsigned int mask; | ||
| 674 | |||
| 675 | /* no need for spu_acquire in interrupt context */ | ||
| 676 | free_elements = ctx->ops->get_mfc_free_elements(ctx); | ||
| 677 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); | ||
| 678 | |||
| 679 | mask = 0; | ||
| 680 | if (free_elements & 0xffff) | ||
| 681 | mask |= POLLOUT; | ||
| 682 | if (tagstatus & ctx->tagwait) | ||
| 683 | mask |= POLLIN; | ||
| 684 | |||
| 685 | kill_fasync(&ctx->mfc_fasync, SIGIO, mask); | ||
| 686 | } | ||
| 687 | } | ||
| 688 | |||
| 689 | static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) | ||
| 690 | { | ||
| 691 | /* See if there is one tag group is complete */ | ||
| 692 | /* FIXME we need locking around tagwait */ | ||
| 693 | *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; | ||
| 694 | ctx->tagwait &= ~*status; | ||
| 695 | if (*status) | ||
| 696 | return 1; | ||
| 697 | |||
| 698 | /* enable interrupt waiting for any tag group, | ||
| 699 | may silently fail if interrupts are already enabled */ | ||
| 700 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); | ||
| 701 | return 0; | ||
| 702 | } | ||
| 703 | |||
| 704 | static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, | ||
| 705 | size_t size, loff_t *pos) | ||
| 706 | { | ||
| 707 | struct spu_context *ctx = file->private_data; | ||
| 708 | int ret = -EINVAL; | ||
| 709 | u32 status; | ||
| 710 | |||
| 711 | if (size != 4) | ||
| 712 | goto out; | ||
| 713 | |||
| 714 | spu_acquire(ctx); | ||
| 715 | if (file->f_flags & O_NONBLOCK) { | ||
| 716 | status = ctx->ops->read_mfc_tagstatus(ctx); | ||
| 717 | if (!(status & ctx->tagwait)) | ||
| 718 | ret = -EAGAIN; | ||
| 719 | else | ||
| 720 | ctx->tagwait &= ~status; | ||
| 721 | } else { | ||
| 722 | ret = spufs_wait(ctx->mfc_wq, | ||
| 723 | spufs_read_mfc_tagstatus(ctx, &status)); | ||
| 724 | } | ||
| 725 | spu_release(ctx); | ||
| 726 | |||
| 727 | if (ret) | ||
| 728 | goto out; | ||
| 729 | |||
| 730 | ret = 4; | ||
| 731 | if (copy_to_user(buffer, &status, 4)) | ||
| 732 | ret = -EFAULT; | ||
| 733 | |||
| 734 | out: | ||
| 735 | return ret; | ||
| 736 | } | ||
| 737 | |||
| 738 | static int spufs_check_valid_dma(struct mfc_dma_command *cmd) | ||
| 739 | { | ||
| 740 | pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, | ||
| 741 | cmd->ea, cmd->size, cmd->tag, cmd->cmd); | ||
| 742 | |||
| 743 | switch (cmd->cmd) { | ||
| 744 | case MFC_PUT_CMD: | ||
| 745 | case MFC_PUTF_CMD: | ||
| 746 | case MFC_PUTB_CMD: | ||
| 747 | case MFC_GET_CMD: | ||
| 748 | case MFC_GETF_CMD: | ||
| 749 | case MFC_GETB_CMD: | ||
| 750 | break; | ||
| 751 | default: | ||
| 752 | pr_debug("invalid DMA opcode %x\n", cmd->cmd); | ||
| 753 | return -EIO; | ||
| 754 | } | ||
| 755 | |||
| 756 | if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { | ||
| 757 | pr_debug("invalid DMA alignment, ea %lx lsa %x\n", | ||
| 758 | cmd->ea, cmd->lsa); | ||
| 759 | return -EIO; | ||
| 760 | } | ||
| 761 | |||
| 762 | switch (cmd->size & 0xf) { | ||
| 763 | case 1: | ||
| 764 | break; | ||
| 765 | case 2: | ||
| 766 | if (cmd->lsa & 1) | ||
| 767 | goto error; | ||
| 768 | break; | ||
| 769 | case 4: | ||
| 770 | if (cmd->lsa & 3) | ||
| 771 | goto error; | ||
| 772 | break; | ||
| 773 | case 8: | ||
| 774 | if (cmd->lsa & 7) | ||
| 775 | goto error; | ||
| 776 | break; | ||
| 777 | case 0: | ||
| 778 | if (cmd->lsa & 15) | ||
| 779 | goto error; | ||
| 780 | break; | ||
| 781 | error: | ||
| 782 | default: | ||
| 783 | pr_debug("invalid DMA alignment %x for size %x\n", | ||
| 784 | cmd->lsa & 0xf, cmd->size); | ||
| 785 | return -EIO; | ||
| 786 | } | ||
| 787 | |||
| 788 | if (cmd->size > 16 * 1024) { | ||
| 789 | pr_debug("invalid DMA size %x\n", cmd->size); | ||
| 790 | return -EIO; | ||
| 791 | } | ||
| 792 | |||
| 793 | if (cmd->tag & 0xfff0) { | ||
| 794 | /* we reserve the higher tag numbers for kernel use */ | ||
| 795 | pr_debug("invalid DMA tag\n"); | ||
| 796 | return -EIO; | ||
| 797 | } | ||
| 798 | |||
| 799 | if (cmd->class) { | ||
| 800 | /* not supported in this version */ | ||
| 801 | pr_debug("invalid DMA class\n"); | ||
| 802 | return -EIO; | ||
| 803 | } | ||
| 804 | |||
| 805 | return 0; | ||
| 806 | } | ||
| 807 | |||
| 808 | static int spu_send_mfc_command(struct spu_context *ctx, | ||
| 809 | struct mfc_dma_command cmd, | ||
| 810 | int *error) | ||
| 811 | { | ||
| 812 | *error = ctx->ops->send_mfc_command(ctx, &cmd); | ||
| 813 | if (*error == -EAGAIN) { | ||
| 814 | /* wait for any tag group to complete | ||
| 815 | so we have space for the new command */ | ||
| 816 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); | ||
| 817 | /* try again, because the queue might be | ||
| 818 | empty again */ | ||
| 819 | *error = ctx->ops->send_mfc_command(ctx, &cmd); | ||
| 820 | if (*error == -EAGAIN) | ||
| 821 | return 0; | ||
| 822 | } | ||
| 823 | return 1; | ||
| 824 | } | ||
| 825 | |||
| 826 | static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | ||
| 827 | size_t size, loff_t *pos) | ||
| 828 | { | ||
| 829 | struct spu_context *ctx = file->private_data; | ||
| 830 | struct mfc_dma_command cmd; | ||
| 831 | int ret = -EINVAL; | ||
| 832 | |||
| 833 | if (size != sizeof cmd) | ||
| 834 | goto out; | ||
| 835 | |||
| 836 | ret = -EFAULT; | ||
| 837 | if (copy_from_user(&cmd, buffer, sizeof cmd)) | ||
| 838 | goto out; | ||
| 839 | |||
| 840 | ret = spufs_check_valid_dma(&cmd); | ||
| 841 | if (ret) | ||
| 842 | goto out; | ||
| 843 | |||
| 844 | spu_acquire_runnable(ctx); | ||
| 845 | if (file->f_flags & O_NONBLOCK) { | ||
| 846 | ret = ctx->ops->send_mfc_command(ctx, &cmd); | ||
| 847 | } else { | ||
| 848 | int status; | ||
| 849 | ret = spufs_wait(ctx->mfc_wq, | ||
| 850 | spu_send_mfc_command(ctx, cmd, &status)); | ||
| 851 | if (status) | ||
| 852 | ret = status; | ||
| 853 | } | ||
| 854 | spu_release(ctx); | ||
| 855 | |||
| 856 | if (ret) | ||
| 857 | goto out; | ||
| 858 | |||
| 859 | ctx->tagwait |= 1 << cmd.tag; | ||
| 860 | |||
| 861 | out: | ||
| 862 | return ret; | ||
| 863 | } | ||
| 864 | |||
| 865 | static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) | ||
| 866 | { | ||
| 867 | struct spu_context *ctx = file->private_data; | ||
| 868 | u32 free_elements, tagstatus; | ||
| 869 | unsigned int mask; | ||
| 870 | |||
| 871 | spu_acquire(ctx); | ||
| 872 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); | ||
| 873 | free_elements = ctx->ops->get_mfc_free_elements(ctx); | ||
| 874 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); | ||
| 875 | spu_release(ctx); | ||
| 876 | |||
| 877 | poll_wait(file, &ctx->mfc_wq, wait); | ||
| 878 | |||
| 879 | mask = 0; | ||
| 880 | if (free_elements & 0xffff) | ||
| 881 | mask |= POLLOUT | POLLWRNORM; | ||
| 882 | if (tagstatus & ctx->tagwait) | ||
| 883 | mask |= POLLIN | POLLRDNORM; | ||
| 884 | |||
| 885 | pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, | ||
| 886 | free_elements, tagstatus, ctx->tagwait); | ||
| 887 | |||
| 888 | return mask; | ||
| 889 | } | ||
| 890 | |||
| 891 | static int spufs_mfc_flush(struct file *file) | ||
| 892 | { | ||
| 893 | struct spu_context *ctx = file->private_data; | ||
| 894 | int ret; | ||
| 895 | |||
| 896 | spu_acquire(ctx); | ||
| 897 | #if 0 | ||
| 898 | /* this currently hangs */ | ||
| 899 | ret = spufs_wait(ctx->mfc_wq, | ||
| 900 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); | ||
| 901 | if (ret) | ||
| 902 | goto out; | ||
| 903 | ret = spufs_wait(ctx->mfc_wq, | ||
| 904 | ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); | ||
| 905 | out: | ||
| 906 | #else | ||
| 907 | ret = 0; | ||
| 908 | #endif | ||
| 909 | spu_release(ctx); | ||
| 910 | |||
| 911 | return ret; | ||
| 912 | } | ||
| 913 | |||
| 914 | static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, | ||
| 915 | int datasync) | ||
| 916 | { | ||
| 917 | return spufs_mfc_flush(file); | ||
| 918 | } | ||
| 919 | |||
| 920 | static int spufs_mfc_fasync(int fd, struct file *file, int on) | ||
| 921 | { | ||
| 922 | struct spu_context *ctx = file->private_data; | ||
| 923 | |||
| 924 | return fasync_helper(fd, file, on, &ctx->mfc_fasync); | ||
| 925 | } | ||
| 926 | |||
| 927 | static struct file_operations spufs_mfc_fops = { | ||
| 928 | .open = spufs_mfc_open, | ||
| 929 | .read = spufs_mfc_read, | ||
| 930 | .write = spufs_mfc_write, | ||
| 931 | .poll = spufs_mfc_poll, | ||
| 932 | .flush = spufs_mfc_flush, | ||
| 933 | .fsync = spufs_mfc_fsync, | ||
| 934 | .fasync = spufs_mfc_fasync, | ||
| 935 | }; | ||
| 936 | |||
| 644 | static void spufs_npc_set(void *data, u64 val) | 937 | static void spufs_npc_set(void *data, u64 val) |
| 645 | { | 938 | { |
| 646 | struct spu_context *ctx = data; | 939 | struct spu_context *ctx = data; |
| @@ -783,6 +1076,7 @@ struct tree_descr spufs_dir_contents[] = { | |||
| 783 | { "signal2", &spufs_signal2_fops, 0666, }, | 1076 | { "signal2", &spufs_signal2_fops, 0666, }, |
| 784 | { "signal1_type", &spufs_signal1_type, 0666, }, | 1077 | { "signal1_type", &spufs_signal1_type, 0666, }, |
| 785 | { "signal2_type", &spufs_signal2_type, 0666, }, | 1078 | { "signal2_type", &spufs_signal2_type, 0666, }, |
| 1079 | { "mfc", &spufs_mfc_fops, 0666, }, | ||
| 786 | { "npc", &spufs_npc_ops, 0666, }, | 1080 | { "npc", &spufs_npc_ops, 0666, }, |
| 787 | { "fpcr", &spufs_fpcr_fops, 0666, }, | 1081 | { "fpcr", &spufs_fpcr_fops, 0666, }, |
| 788 | { "decr", &spufs_decr_ops, 0666, }, | 1082 | { "decr", &spufs_decr_ops, 0666, }, |
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index 5445719bff79..a13a8b5a014d 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c | |||
| @@ -232,6 +232,59 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx) | |||
| 232 | spin_unlock_irq(&ctx->spu->register_lock); | 232 | spin_unlock_irq(&ctx->spu->register_lock); |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode) | ||
| 236 | { | ||
| 237 | struct spu_problem *prob = ctx->spu->problem; | ||
| 238 | int ret; | ||
| 239 | |||
| 240 | spin_lock_irq(&ctx->spu->register_lock); | ||
| 241 | ret = -EAGAIN; | ||
| 242 | if (in_be32(&prob->dma_querytype_RW)) | ||
| 243 | goto out; | ||
| 244 | ret = 0; | ||
| 245 | out_be32(&prob->dma_querymask_RW, mask); | ||
| 246 | out_be32(&prob->dma_querytype_RW, mode); | ||
| 247 | out: | ||
| 248 | spin_unlock_irq(&ctx->spu->register_lock); | ||
| 249 | return ret; | ||
| 250 | } | ||
| 251 | |||
| 252 | static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx) | ||
| 253 | { | ||
| 254 | return in_be32(&ctx->spu->problem->dma_tagstatus_R); | ||
| 255 | } | ||
| 256 | |||
| 257 | static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx) | ||
| 258 | { | ||
| 259 | return in_be32(&ctx->spu->problem->dma_qstatus_R); | ||
| 260 | } | ||
| 261 | |||
| 262 | static int spu_hw_send_mfc_command(struct spu_context *ctx, | ||
| 263 | struct mfc_dma_command *cmd) | ||
| 264 | { | ||
| 265 | u32 status; | ||
| 266 | struct spu_problem *prob = ctx->spu->problem; | ||
| 267 | |||
| 268 | spin_lock_irq(&ctx->spu->register_lock); | ||
| 269 | out_be32(&prob->mfc_lsa_W, cmd->lsa); | ||
| 270 | out_be64(&prob->mfc_ea_W, cmd->ea); | ||
| 271 | out_be32(&prob->mfc_union_W.by32.mfc_size_tag32, | ||
| 272 | cmd->size << 16 | cmd->tag); | ||
| 273 | out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32, | ||
| 274 | cmd->class << 16 | cmd->cmd); | ||
| 275 | status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32); | ||
| 276 | spin_unlock_irq(&ctx->spu->register_lock); | ||
| 277 | |||
| 278 | switch (status & 0xffff) { | ||
| 279 | case 0: | ||
| 280 | return 0; | ||
| 281 | case 2: | ||
| 282 | return -EAGAIN; | ||
| 283 | default: | ||
| 284 | return -EINVAL; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 235 | struct spu_context_ops spu_hw_ops = { | 288 | struct spu_context_ops spu_hw_ops = { |
| 236 | .mbox_read = spu_hw_mbox_read, | 289 | .mbox_read = spu_hw_mbox_read, |
| 237 | .mbox_stat_read = spu_hw_mbox_stat_read, | 290 | .mbox_stat_read = spu_hw_mbox_stat_read, |
| @@ -252,4 +305,8 @@ struct spu_context_ops spu_hw_ops = { | |||
| 252 | .get_ls = spu_hw_get_ls, | 305 | .get_ls = spu_hw_get_ls, |
| 253 | .runcntl_write = spu_hw_runcntl_write, | 306 | .runcntl_write = spu_hw_runcntl_write, |
| 254 | .runcntl_stop = spu_hw_runcntl_stop, | 307 | .runcntl_stop = spu_hw_runcntl_stop, |
| 308 | .set_mfc_query = spu_hw_set_mfc_query, | ||
| 309 | .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus, | ||
| 310 | .get_mfc_free_elements = spu_hw_get_mfc_free_elements, | ||
| 311 | .send_mfc_command = spu_hw_send_mfc_command, | ||
| 255 | }; | 312 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 963182fbd1aa..bf652cd77000 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
| @@ -180,6 +180,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) | |||
| 180 | spu->ibox_callback = spufs_ibox_callback; | 180 | spu->ibox_callback = spufs_ibox_callback; |
| 181 | spu->wbox_callback = spufs_wbox_callback; | 181 | spu->wbox_callback = spufs_wbox_callback; |
| 182 | spu->stop_callback = spufs_stop_callback; | 182 | spu->stop_callback = spufs_stop_callback; |
| 183 | spu->mfc_callback = spufs_mfc_callback; | ||
| 183 | mb(); | 184 | mb(); |
| 184 | spu_unmap_mappings(ctx); | 185 | spu_unmap_mappings(ctx); |
| 185 | spu_restore(&ctx->csa, spu); | 186 | spu_restore(&ctx->csa, spu); |
| @@ -197,6 +198,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) | |||
| 197 | spu->ibox_callback = NULL; | 198 | spu->ibox_callback = NULL; |
| 198 | spu->wbox_callback = NULL; | 199 | spu->wbox_callback = NULL; |
| 199 | spu->stop_callback = NULL; | 200 | spu->stop_callback = NULL; |
| 201 | spu->mfc_callback = NULL; | ||
| 200 | spu->mm = NULL; | 202 | spu->mm = NULL; |
| 201 | spu->pid = 0; | 203 | spu->pid = 0; |
| 202 | spu->prio = MAX_PRIO; | 204 | spu->prio = MAX_PRIO; |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index db2601f0abd5..57d687ca3f03 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
| @@ -55,13 +55,27 @@ struct spu_context { | |||
| 55 | wait_queue_head_t ibox_wq; | 55 | wait_queue_head_t ibox_wq; |
| 56 | wait_queue_head_t wbox_wq; | 56 | wait_queue_head_t wbox_wq; |
| 57 | wait_queue_head_t stop_wq; | 57 | wait_queue_head_t stop_wq; |
| 58 | wait_queue_head_t mfc_wq; | ||
| 58 | struct fasync_struct *ibox_fasync; | 59 | struct fasync_struct *ibox_fasync; |
| 59 | struct fasync_struct *wbox_fasync; | 60 | struct fasync_struct *wbox_fasync; |
| 61 | struct fasync_struct *mfc_fasync; | ||
| 62 | u32 tagwait; | ||
| 60 | struct spu_context_ops *ops; | 63 | struct spu_context_ops *ops; |
| 61 | struct work_struct reap_work; | 64 | struct work_struct reap_work; |
| 62 | u64 flags; | 65 | u64 flags; |
| 63 | }; | 66 | }; |
| 64 | 67 | ||
| 68 | struct mfc_dma_command { | ||
| 69 | int32_t pad; /* reserved */ | ||
| 70 | uint32_t lsa; /* local storage address */ | ||
| 71 | uint64_t ea; /* effective address */ | ||
| 72 | uint16_t size; /* transfer size */ | ||
| 73 | uint16_t tag; /* command tag */ | ||
| 74 | uint16_t class; /* class ID */ | ||
| 75 | uint16_t cmd; /* command opcode */ | ||
| 76 | }; | ||
| 77 | |||
| 78 | |||
| 65 | /* SPU context query/set operations. */ | 79 | /* SPU context query/set operations. */ |
| 66 | struct spu_context_ops { | 80 | struct spu_context_ops { |
| 67 | int (*mbox_read) (struct spu_context * ctx, u32 * data); | 81 | int (*mbox_read) (struct spu_context * ctx, u32 * data); |
| @@ -84,6 +98,11 @@ struct spu_context_ops { | |||
| 84 | char*(*get_ls) (struct spu_context * ctx); | 98 | char*(*get_ls) (struct spu_context * ctx); |
| 85 | void (*runcntl_write) (struct spu_context * ctx, u32 data); | 99 | void (*runcntl_write) (struct spu_context * ctx, u32 data); |
| 86 | void (*runcntl_stop) (struct spu_context * ctx); | 100 | void (*runcntl_stop) (struct spu_context * ctx); |
| 101 | int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode); | ||
| 102 | u32 (*read_mfc_tagstatus)(struct spu_context * ctx); | ||
| 103 | u32 (*get_mfc_free_elements)(struct spu_context *ctx); | ||
| 104 | int (*send_mfc_command)(struct spu_context *ctx, | ||
| 105 | struct mfc_dma_command *cmd); | ||
| 87 | }; | 106 | }; |
| 88 | 107 | ||
| 89 | extern struct spu_context_ops spu_hw_ops; | 108 | extern struct spu_context_ops spu_hw_ops; |
| @@ -159,5 +178,6 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data); | |||
| 159 | void spufs_ibox_callback(struct spu *spu); | 178 | void spufs_ibox_callback(struct spu *spu); |
| 160 | void spufs_wbox_callback(struct spu *spu); | 179 | void spufs_wbox_callback(struct spu *spu); |
| 161 | void spufs_stop_callback(struct spu *spu); | 180 | void spufs_stop_callback(struct spu *spu); |
| 181 | void spufs_mfc_callback(struct spu *spu); | ||
| 162 | 182 | ||
| 163 | #endif | 183 | #endif |
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 212db28531fa..97898d5d34e5 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c | |||
| @@ -2145,7 +2145,8 @@ static void init_priv1(struct spu_state *csa) | |||
| 2145 | csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | | 2145 | csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | |
| 2146 | CLASS1_ENABLE_STORAGE_FAULT_INTR; | 2146 | CLASS1_ENABLE_STORAGE_FAULT_INTR; |
| 2147 | csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | | 2147 | csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | |
| 2148 | CLASS2_ENABLE_SPU_HALT_INTR; | 2148 | CLASS2_ENABLE_SPU_HALT_INTR | |
| 2149 | CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR; | ||
| 2149 | } | 2150 | } |
| 2150 | 2151 | ||
| 2151 | static void init_priv2(struct spu_state *csa) | 2152 | static void init_priv2(struct spu_state *csa) |
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index b5c90d6fdceb..8564b8234069 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
| @@ -137,6 +137,7 @@ struct spu { | |||
| 137 | void (* wbox_callback)(struct spu *spu); | 137 | void (* wbox_callback)(struct spu *spu); |
| 138 | void (* ibox_callback)(struct spu *spu); | 138 | void (* ibox_callback)(struct spu *spu); |
| 139 | void (* stop_callback)(struct spu *spu); | 139 | void (* stop_callback)(struct spu *spu); |
| 140 | void (* mfc_callback)(struct spu *spu); | ||
| 140 | 141 | ||
| 141 | char irq_c0[8]; | 142 | char irq_c0[8]; |
| 142 | char irq_c1[8]; | 143 | char irq_c1[8]; |
