Skip to content

Commit

Permalink
Merge branch 'merge' of master.kernel.org:/pub/scm/linux/kernel/git/p…
Browse files Browse the repository at this point in the history
…aulus/powerpc

* 'merge' of master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc:
  [POWERPC] sys_move_pages should be callable from an SPU
  [POWERPC] Wire up sys_epoll_pwait
  [POWERPC] Allocate syscall number for sys_getcpu
  [POWERPC] update cell_defconfig
  [POWERPC] ps3: always make sure were running on a PS3
  [POWERPC] Fix spu SLB invalidations
  [POWERPC] avoid SPU_ACTIVATE_NOWAKE optimization
  [POWERPC] spufs: fix possible memory corruption is spufs_mem_write
  • Loading branch information
Linus Torvalds committed Mar 13, 2007
2 parents 44a5085 + 7b3c384 commit 8b9909d
Show file tree
Hide file tree
Showing 18 changed files with 263 additions and 134 deletions.
151 changes: 130 additions & 21 deletions arch/powerpc/configs/cell_defconfig

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions arch/powerpc/mm/hash_utils_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,9 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
"non-cacheable mapping\n");
psize = mmu_vmalloc_psize = MMU_PAGE_4K;
}
#ifdef CONFIG_SPE_BASE
spu_flush_all_slbs(mm);
#endif
}
if (user_region) {
if (psize != get_paca()->context.user_psize) {
Expand Down Expand Up @@ -759,6 +762,9 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
mmu_psize_defs[MMU_PAGE_4K].sllp;
get_paca()->context = mm->context;
slb_flush_and_rebolt();
#ifdef CONFIG_SPE_BASE
spu_flush_all_slbs(mm);
#endif
}
}
if (mm->context.user_psize == MMU_PAGE_64K)
Expand Down
4 changes: 4 additions & 0 deletions arch/powerpc/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <asm/machdep.h>
#include <asm/cputable.h>
#include <asm/tlb.h>
#include <asm/spu.h>

#include <linux/sysctl.h>

Expand Down Expand Up @@ -513,6 +514,9 @@ int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff)
if ((addr + len) > 0x100000000UL)
err = open_high_hpage_areas(current->mm,
HTLB_AREA_MASK(addr, len));
#ifdef CONFIG_SPE_BASE
spu_flush_all_slbs(current->mm);
#endif
if (err) {
printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
" failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
Expand Down
81 changes: 69 additions & 12 deletions arch/powerpc/platforms/cell/spu_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,61 @@
const struct spu_management_ops *spu_management_ops;
const struct spu_priv1_ops *spu_priv1_ops;

static struct list_head spu_list[MAX_NUMNODES];
static LIST_HEAD(spu_full_list);
static DEFINE_MUTEX(spu_mutex);
static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED;

EXPORT_SYMBOL_GPL(spu_priv1_ops);

void spu_invalidate_slbs(struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;

if (spu_mfc_sr1_get(spu) & MFC_STATE1_RELOCATE_MASK)
out_be64(&priv2->slb_invalidate_all_W, 0UL);
}
EXPORT_SYMBOL_GPL(spu_invalidate_slbs);

/* This is called by the MM core when a segment size is changed, to
* request a flush of all the SPEs using a given mm
*/
void spu_flush_all_slbs(struct mm_struct *mm)
{
struct spu *spu;
unsigned long flags;

spin_lock_irqsave(&spu_list_lock, flags);
list_for_each_entry(spu, &spu_full_list, full_list) {
if (spu->mm == mm)
spu_invalidate_slbs(spu);
}
spin_unlock_irqrestore(&spu_list_lock, flags);
}

/* The hack below stinks... try to do something better one of
* these days... Does it even work properly with NR_CPUS == 1 ?
*/
static inline void mm_needs_global_tlbie(struct mm_struct *mm)
{
int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;

/* Global TLBIE broadcast required with SPEs. */
__cpus_setall(&mm->cpu_vm_mask, nr);
}

void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
{
unsigned long flags;

spin_lock_irqsave(&spu_list_lock, flags);
spu->mm = mm;
spin_unlock_irqrestore(&spu_list_lock, flags);
if (mm)
mm_needs_global_tlbie(mm);
}
EXPORT_SYMBOL_GPL(spu_associate_mm);

static int __spu_trap_invalid_dma(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
Expand Down Expand Up @@ -74,6 +127,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
struct spu_priv2 __iomem *priv2 = spu->priv2;
struct mm_struct *mm = spu->mm;
u64 esid, vsid, llp;
int psize;

pr_debug("%s\n", __FUNCTION__);

Expand All @@ -90,22 +144,25 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
case USER_REGION_ID:
#ifdef CONFIG_HUGETLB_PAGE
if (in_hugepage_area(mm->context, ea))
llp = mmu_psize_defs[mmu_huge_psize].sllp;
psize = mmu_huge_psize;
else
#endif
llp = mmu_psize_defs[mmu_virtual_psize].sllp;
psize = mm->context.user_psize;
vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
SLB_VSID_USER | llp;
SLB_VSID_USER;
break;
case VMALLOC_REGION_ID:
llp = mmu_psize_defs[mmu_virtual_psize].sllp;
if (ea < VMALLOC_END)
psize = mmu_vmalloc_psize;
else
psize = mmu_io_psize;
vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
SLB_VSID_KERNEL | llp;
SLB_VSID_KERNEL;
break;
case KERNEL_REGION_ID:
llp = mmu_psize_defs[mmu_linear_psize].sllp;
psize = mmu_linear_psize;
vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
SLB_VSID_KERNEL | llp;
SLB_VSID_KERNEL;
break;
default:
/* Future: support kernel segments so that drivers
Expand All @@ -114,9 +171,10 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
pr_debug("invalid region access at %016lx\n", ea);
return 1;
}
llp = mmu_psize_defs[psize].sllp;

out_be64(&priv2->slb_index_W, spu->slb_replace);
out_be64(&priv2->slb_vsid_RW, vsid);
out_be64(&priv2->slb_vsid_RW, vsid | llp);
out_be64(&priv2->slb_esid_RW, esid);

spu->slb_replace++;
Expand Down Expand Up @@ -330,10 +388,6 @@ static void spu_free_irqs(struct spu *spu)
free_irq(spu->irqs[2], spu);
}

static struct list_head spu_list[MAX_NUMNODES];
static LIST_HEAD(spu_full_list);
static DEFINE_MUTEX(spu_mutex);

static void spu_init_channels(struct spu *spu)
{
static const struct {
Expand Down Expand Up @@ -593,6 +647,7 @@ static int __init create_spu(void *data)
struct spu *spu;
int ret;
static int number;
unsigned long flags;

ret = -ENOMEM;
spu = kzalloc(sizeof (*spu), GFP_KERNEL);
Expand Down Expand Up @@ -620,8 +675,10 @@ static int __init create_spu(void *data)
goto out_free_irqs;

mutex_lock(&spu_mutex);
spin_lock_irqsave(&spu_list_lock, flags);
list_add(&spu->list, &spu_list[spu->node]);
list_add(&spu->full_list, &spu_full_list);
spin_unlock_irqrestore(&spu_list_lock, flags);
mutex_unlock(&spu_mutex);

goto out;
Expand Down
24 changes: 14 additions & 10 deletions arch/powerpc/platforms/cell/spufs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ static ssize_t
spufs_mem_read(struct file *file, char __user *buffer,
size_t size, loff_t *pos)
{
int ret;
struct spu_context *ctx = file->private_data;
ssize_t ret;

spu_acquire(ctx);
ret = __spufs_mem_read(ctx, buffer, size, pos);
Expand All @@ -74,25 +74,29 @@ spufs_mem_read(struct file *file, char __user *buffer,

static ssize_t
spufs_mem_write(struct file *file, const char __user *buffer,
size_t size, loff_t *pos)
size_t size, loff_t *ppos)
{
struct spu_context *ctx = file->private_data;
char *local_store;
loff_t pos = *ppos;
int ret;

size = min_t(ssize_t, LS_SIZE - *pos, size);
if (size <= 0)
if (pos < 0)
return -EINVAL;
if (pos > LS_SIZE)
return -EFBIG;
*pos += size;
if (size > LS_SIZE - pos)
size = LS_SIZE - pos;

spu_acquire(ctx);

local_store = ctx->ops->get_ls(ctx);
ret = copy_from_user(local_store + *pos - size,
buffer, size) ? -EFAULT : size;

ret = copy_from_user(local_store + pos, buffer, size);
spu_release(ctx);
return ret;

if (ret)
return -EFAULT;
*ppos = pos + size;
return size;
}

static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/platforms/cell/spufs/run.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
int ret;
unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;

ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE);
ret = spu_acquire_runnable(ctx, 0);
if (ret)
return ret;

Expand All @@ -155,7 +155,7 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
spu_release(ctx);
ret = spu_setup_isolated(ctx);
if (!ret)
ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE);
ret = spu_acquire_runnable(ctx, 0);
}

/* if userspace has set the runcntrl register (eg, to issue an
Expand Down
20 changes: 4 additions & 16 deletions arch/powerpc/platforms/cell/spufs/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,6 @@ static void spu_remove_from_active_list(struct spu *spu)
mutex_unlock(&spu_prio->active_mutex[node]);
}

static inline void mm_needs_global_tlbie(struct mm_struct *mm)
{
int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;

/* Global TLBIE broadcast required with SPEs. */
__cpus_setall(&mm->cpu_vm_mask, nr);
}

static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);

static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
Expand Down Expand Up @@ -167,8 +159,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
ctx->spu = spu;
ctx->ops = &spu_hw_ops;
spu->pid = current->pid;
spu->mm = ctx->owner;
mm_needs_global_tlbie(spu->mm);
spu_associate_mm(spu, ctx->owner);
spu->ibox_callback = spufs_ibox_callback;
spu->wbox_callback = spufs_wbox_callback;
spu->stop_callback = spufs_stop_callback;
Expand Down Expand Up @@ -205,7 +196,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
spu->stop_callback = NULL;
spu->mfc_callback = NULL;
spu->dma_callback = NULL;
spu->mm = NULL;
spu_associate_mm(spu, NULL);
spu->pid = 0;
ctx->ops = &spu_backing_ops;
ctx->spu = NULL;
Expand Down Expand Up @@ -263,7 +254,6 @@ static void spu_prio_wait(struct spu_context *ctx)
{
DEFINE_WAIT(wait);

set_bit(SPU_SCHED_WAKE, &ctx->sched_flags);
prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
if (!signal_pending(current)) {
mutex_unlock(&ctx->state_mutex);
Expand All @@ -272,7 +262,6 @@ static void spu_prio_wait(struct spu_context *ctx)
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&ctx->stop_wq, &wait);
clear_bit(SPU_SCHED_WAKE, &ctx->sched_flags);
}

/**
Expand All @@ -292,7 +281,7 @@ static void spu_reschedule(struct spu *spu)
best = sched_find_first_bit(spu_prio->bitmap);
if (best < MAX_PRIO) {
struct spu_context *ctx = spu_grab_context(best);
if (ctx && test_bit(SPU_SCHED_WAKE, &ctx->sched_flags))
if (ctx)
wake_up(&ctx->stop_wq);
}
spin_unlock(&spu_prio->runq_lock);
Expand Down Expand Up @@ -414,8 +403,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
}

spu_add_to_rq(ctx);
if (!(flags & SPU_ACTIVATE_NOWAKE))
spu_prio_wait(ctx);
spu_prio_wait(ctx);
spu_del_from_rq(ctx);
} while (!signal_pending(current));

Expand Down
6 changes: 2 additions & 4 deletions arch/powerpc/platforms/cell/spufs/spufs.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct spu_gang;

/* ctx->sched_flags */
enum {
SPU_SCHED_WAKE = 0,
SPU_SCHED_WAKE = 0, /* currently unused */
};

struct spu_context {
Expand Down Expand Up @@ -191,9 +191,7 @@ void spu_forget(struct spu_context *ctx);
int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
void spu_acquire_saved(struct spu_context *ctx);
int spu_acquire_exclusive(struct spu_context *ctx);
enum {
SPU_ACTIVATE_NOWAKE = 1,
};

int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
void spu_yield(struct spu_context *ctx);
Expand Down
Loading

0 comments on commit 8b9909d

Please sign in to comment.