{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->local_store = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->local_store = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->local_store = NULL;
+ spin_unlock(&ctx->mapping_lock);
return 0;
}
static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
unsigned long address)
{
- struct spu_context *ctx = vma->vm_file->private_data;
- unsigned long pfn, offset = address - vma->vm_start;
+ struct spu_context *ctx = vma->vm_file->private_data;
+ unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+ struct spu_state *csa = &ctx->csa;
+ int psize;
- offset += vma->vm_pgoff << PAGE_SHIFT;
+ /* Check what page size we are using */
+ psize = get_slice_psize(vma->vm_mm, address);
+ /* Some sanity checking */
+ BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+ /* Wow, 64K, cool, we need to align the address though */
+ if (csa->use_big_pages) {
+ BUG_ON(vma->vm_start & 0xffff);
+ address &= ~0xfffful;
+ }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
+ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
if (offset >= LS_SIZE)
return NOPFN_SIGBUS;
+ pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+ addr0, address, offset);
+
spu_acquire(ctx);
if (ctx->state == SPU_STATE_SAVED) {
.nopfn = spufs_mem_mmap_nopfn,
};
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
-{
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_SPU_FS_64K_LS
+ struct spu_context *ctx = file->private_data;
+ struct spu_state *csa = &ctx->csa;
+
+ /* Sanity check VMA alignment */
+ if (csa->use_big_pages) {
+ pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+ " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+ vma->vm_pgoff);
+ if (vma->vm_start & 0xffff)
+ return -EINVAL;
+ if (vma->vm_pgoff & 0xf)
+ return -EINVAL;
+ }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
return 0;
}
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_state *csa = &ctx->csa;
+
+ /* If not using big pages, fallback to normal MM g_u_a */
+ if (!csa->use_big_pages)
+ return current->mm->get_unmapped_area(file, addr, len,
+ pgoff, flags);
+
+ /* Else, try to obtain a 64K pages slice */
+ return slice_get_unmapped_area(addr, len, flags,
+ MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
static const struct file_operations spufs_mem_fops = {
- .open = spufs_mem_open,
- .read = spufs_mem_read,
- .write = spufs_mem_write,
- .llseek = generic_file_llseek,
- .mmap = spufs_mem_mmap,
+ .open = spufs_mem_open,
+ .read = spufs_mem_read,
+ .write = spufs_mem_write,
+ .llseek = generic_file_llseek,
+ .mmap = spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+ .get_unmapped_area = spufs_get_unmapped_area,
+#endif
};
static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->cntl = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->cntl = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return simple_attr_open(inode, file, spufs_cntl_get,
spufs_cntl_set, "0x%08lx");
}
+static int
+spufs_cntl_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ simple_attr_close(inode, file);
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->cntl = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_cntl_fops = {
.open = spufs_cntl_open,
- .release = simple_attr_close,
+ .release = spufs_cntl_release,
.read = simple_attr_read,
.write = simple_attr_write,
.mmap = spufs_cntl_mmap,
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->signal1 = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->signal1 = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_signal1_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->signal1 = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
{
static const struct file_operations spufs_signal1_fops = {
.open = spufs_signal1_open,
+ .release = spufs_signal1_release,
.read = spufs_signal1_read,
.write = spufs_signal1_write,
.mmap = spufs_signal1_mmap,
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->signal2 = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->signal2 = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_signal2_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->signal2 = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
{
static const struct file_operations spufs_signal2_fops = {
.open = spufs_signal2_open,
+ .release = spufs_signal2_release,
.read = spufs_signal2_read,
.write = spufs_signal2_write,
.mmap = spufs_signal2_mmap,
struct spu_context *ctx = i->i_ctx;
file->private_data = i->i_ctx;
- ctx->mss = inode->i_mapping;
- smp_wmb();
+
+ spin_lock(&ctx->mapping_lock);
+ if (!i->i_openers++)
+ ctx->mss = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_mss_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->mss = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_mss_fops = {
.open = spufs_mss_open,
+ .release = spufs_mss_release,
.mmap = spufs_mss_mmap,
};
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+ spin_lock(&ctx->mapping_lock);
file->private_data = i->i_ctx;
- ctx->psmap = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->psmap = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_psmap_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->psmap = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_psmap_fops = {
.open = spufs_psmap_open,
+ .release = spufs_psmap_release,
.mmap = spufs_psmap_mmap,
};
if (atomic_read(&inode->i_count) != 1)
return -EBUSY;
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->mfc = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->mfc = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_mfc_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->mfc = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
/* interrupt-level mfc callback function. */
void spufs_mfc_callback(struct spu *spu)
{
if (ret)
goto out;
- spu_acquire_runnable(ctx, 0);
+ ret = spu_acquire_runnable(ctx, 0);
+ if (ret)
+ goto out;
+
if (file->f_flags & O_NONBLOCK) {
ret = ctx->ops->send_mfc_command(ctx, &cmd);
} else {
static const struct file_operations spufs_mfc_fops = {
.open = spufs_mfc_open,
+ .release = spufs_mfc_release,
.read = spufs_mfc_read,
.write = spufs_mfc_write,
.poll = spufs_mfc_poll,