From 6291ed3c04d5c83c26e77d4fa47e06d0416be81d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 4 Jun 2007 10:49:05 +1000 Subject: [POWERPC] pasemi: Fix iommu + 64K PAGE_SIZE bug The powerpc iommu code was refactored by Linas back in the 2.6.20 time frame to map 4K pages from the generic code, but I had forgotten to go back and fix my platform driver before submitting it. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/iommu.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 95fa6a7d15e..f33b21b9f5d 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -31,8 +31,6 @@ #define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) #define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) -#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT) - #define IOB_BASE 0xe0000000 #define IOB_SIZE 0x3000 /* Configuration registers */ @@ -97,9 +95,6 @@ static void iobmap_build(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { @@ -125,9 +120,6 @@ static void iobmap_free(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { -- cgit v1.2.3 From 8f18a158192ef6dc63a572bdbbdf5613cfbbe2e4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs: Refuse to load the module when not running on cell As noticed by David Woodhouse, it's currently possible to mount spufs on any machine, which means that it actually will get mounted by fedora. This refuses to load the module on platforms that have no support for SPUs. Cc: David Woodhouse Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7150730e2ff..01c4805986f 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -600,6 +600,10 @@ spufs_create_root(struct super_block *sb, void *data) struct inode *inode; int ret; + ret = -ENODEV; + if (!spu_management_ops) + goto out; + ret = -ENOMEM; inode = spufs_new_inode(sb, S_IFDIR | 0775); if (!inode) -- cgit v1.2.3 From ce92987baba60bc082b9eedddfaf4ae3f8435dac Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs: Hook up spufs_release_mem Currently spufs_mem_release and the mem file doesn't have any release method hooked up, leading to leaks everytime is used. Signed-off-by: Christoph Hellwig Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 45614c73c78..89a50110a3c 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -217,6 +217,7 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, + .release = spufs_mem_release, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, -- cgit v1.2.3 From 877907d37da9694a34adc9dc3e2ce09400148cb5 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs: Fix gang destroy leaks Previously, closing a SPE gang that still has contexts would trigger a WARN_ON, and leak the allocated gang. This change fixes the problem by using the gang's reference counts to destroy the gang instead. The gangs will persist until their last reference (be it context or open file handle) is gone. Also, avoid using statements with side-effects in a WARN_ON(). Signed-off-by: Jeremy Kerr Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 40 ++++--------------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 01c4805986f..fe960ddbde7 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -349,37 +349,6 @@ out: return ret; } -static int spufs_rmgang(struct inode *root, struct dentry *dir) -{ - /* FIXME: this fails if the dir is not empty, - which causes a leak of gangs. */ - return simple_rmdir(root, dir); -} - -static int spufs_gang_close(struct inode *inode, struct file *file) -{ - struct inode *parent; - struct dentry *dir; - int ret; - - dir = file->f_path.dentry; - parent = dir->d_parent->d_inode; - - ret = spufs_rmgang(parent, dir); - WARN_ON(ret); - - return dcache_dir_close(inode, file); -} - -const struct file_operations spufs_gang_fops = { - .open = dcache_dir_open, - .release = spufs_gang_close, - .llseek = dcache_dir_lseek, - .read = generic_read_dir, - .readdir = dcache_readdir, - .fsync = simple_sync_file, -}; - static int spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) { @@ -407,7 +376,6 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) inode->i_fop = &simple_dir_operations; d_instantiate(dentry, inode); - dget(dentry); dir->i_nlink++; dentry->d_inode->i_nlink++; return ret; @@ -437,7 +405,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) goto out; } - filp->f_op = &spufs_gang_fops; + filp->f_op = &simple_dir_operations; fd_install(ret, filp); out: return ret; @@ -458,8 +426,10 @@ static int spufs_create_gang(struct inode *inode, * in error path of *_open(). */ ret = spufs_gang_open(dget(dentry), mntget(mnt)); - if (ret < 0) - WARN_ON(spufs_rmgang(inode, dentry)); + if (ret < 0) { + int err = simple_rmdir(inode, dentry); + WARN_ON(err); + } out: mutex_unlock(&inode->i_mutex); -- cgit v1.2.3 From 89df00855beabfa700f9a9ed52f0983bdc4b021d Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs: Free mm if spufs_fill_dir() failed In case spufs_fill_dir() fails only put_spu_context() gets called for cleanup and the acquired mm_struct never gets freed. Signed-off-by: Sebastian Siewior Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index fe960ddbde7..08356813977 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -274,6 +274,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, goto out; out_free_ctx: + spu_forget(ctx); put_spu_context(ctx); out_iput: iput(inode); -- cgit v1.2.3 From 47d3a5faa3f72186f769ed9579c630afb8433f2b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs: Synchronize pte invalidation vs ps close Make sure the mapping_lock also protects access to the various address_space pointers used for tearing down the ptes on a spu context switch. Because unmap_mapping_range can sleep we need to turn mapping_lock from a spinlock into a sleeping mutex. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/context.c | 4 ++- arch/powerpc/platforms/cell/spufs/file.c | 56 ++++++++++++++--------------- arch/powerpc/platforms/cell/spufs/spufs.h | 2 +- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 8654749e317..7c51cb54bca 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -39,7 +39,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) if (spu_init_csa(&ctx->csa)) goto out_free; spin_lock_init(&ctx->mmio_lock); - spin_lock_init(&ctx->mapping_lock); + mutex_init(&ctx->mapping_lock); kref_init(&ctx->kref); mutex_init(&ctx->state_mutex); mutex_init(&ctx->run_mutex); @@ -103,6 +103,7 @@ void spu_forget(struct spu_context *ctx) void spu_unmap_mappings(struct spu_context *ctx) { + mutex_lock(&ctx->mapping_lock); if (ctx->local_store) unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); if (ctx->mfc) @@ -117,6 +118,7 @@ void spu_unmap_mappings(struct spu_context *ctx) unmap_mapping_range(ctx->mss, 0, 0x1000, 1); if (ctx->psmap) unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); + mutex_unlock(&ctx->mapping_lock); } /** diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 89a50110a3c..b1e7e2f8a2e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -45,11 +45,11 @@ spufs_mem_open(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); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->local_store = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -59,10 +59,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->local_store = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -310,11 +310,11 @@ static int spufs_cntl_open(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); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->cntl = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx"); } @@ -327,10 +327,10 @@ spufs_cntl_release(struct inode *inode, struct file *file) simple_attr_close(inode, file); - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->cntl = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -813,11 +813,11 @@ static int spufs_signal1_open(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); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal1 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -827,10 +827,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal1 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -937,11 +937,11 @@ static int spufs_signal2_open(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); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal2 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -951,10 +951,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal2 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1155,10 +1155,10 @@ static int spufs_mss_open(struct inode *inode, struct file *file) file->private_data = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!i->i_openers++) ctx->mss = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1168,10 +1168,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mss = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1212,11 +1212,11 @@ static int spufs_psmap_open(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); + mutex_lock(&ctx->mapping_lock); file->private_data = i->i_ctx; if (!i->i_openers++) ctx->psmap = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1226,10 +1226,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->psmap = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1282,11 +1282,11 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) if (atomic_read(&inode->i_count) != 1) return -EBUSY; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->mfc = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1296,10 +1296,10 @@ 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); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mfc = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 0a947fd7de5..47617e8014a 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -55,7 +55,7 @@ struct spu_context { struct address_space *signal2; /* 'signal2' area mappings. */ struct address_space *mss; /* 'mss' area mappings. */ struct address_space *psmap; /* 'psmap' area mappings. */ - spinlock_t mapping_lock; + struct mutex mapping_lock; u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; -- cgit v1.2.3 From bb5db29aa0379f0f3ef857a3a3715f17261c611b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jun 2007 23:26:51 +1000 Subject: [POWERPC] spufs scheduler: Fix wakeup races Fix the race between checking for contexts on the runqueue and actually waking them in spu_deactive and spu_yield. The guts of spu_reschedule are split into a new helper called grab_runnable_context which shows if there is a runnable thread below a specified priority and if yes removes if from the runqueue and uses it. This function is used by the new __spu_deactivate hepler shared by preemption and spu_yield to grab a new context before deactivating a specified priority and if yes removes if from the runqueue and uses it. This function is used by the new __spu_deactivate hepler shared by preemption and spu_yield to grab a new context before deactivating the old one. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 159 +++++++++++++++--------------- 1 file changed, 77 insertions(+), 82 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index b6ecb30e7d5..68fcdc4515a 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -93,43 +93,6 @@ void spu_stop_tick(struct spu_context *ctx) } } -void spu_sched_tick(struct work_struct *work) -{ - struct spu_context *ctx = - container_of(work, struct spu_context, sched_work.work); - struct spu *spu; - int preempted = 0; - - /* - * If this context is being stopped avoid rescheduling from the - * scheduler tick because we would block on the state_mutex. - * The caller will yield the spu later on anyway. - */ - if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) - return; - - mutex_lock(&ctx->state_mutex); - spu = ctx->spu; - if (spu) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best <= ctx->prio) { - spu_deactivate(ctx); - preempted = 1; - } - } - mutex_unlock(&ctx->state_mutex); - - if (preempted) { - /* - * We need to break out of the wait loop in spu_run manually - * to ensure this context gets put on the runqueue again - * ASAP. - */ - wake_up(&ctx->stop_wq); - } else - spu_start_tick(ctx); -} - /** * spu_add_to_active_list - add spu to active list * @spu: spu to add to the active list @@ -273,34 +236,6 @@ static void spu_prio_wait(struct spu_context *ctx) remove_wait_queue(&ctx->stop_wq, &wait); } -/** - * spu_reschedule - try to find a runnable context for a spu - * @spu: spu available - * - * This function is called whenever a spu becomes idle. It looks for the - * most suitable runnable spu context and schedules it for execution. - */ -static void spu_reschedule(struct spu *spu) -{ - int best; - - spu_free(spu); - - spin_lock(&spu_prio->runq_lock); - best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - struct list_head *rq = &spu_prio->runq[best]; - struct spu_context *ctx; - - BUG_ON(list_empty(rq)); - - ctx = list_entry(rq->next, struct spu_context, rq); - __spu_del_from_rq(ctx); - wake_up(&ctx->stop_wq); - } - spin_unlock(&spu_prio->runq_lock); -} - static struct spu *spu_get_idle(struct spu_context *ctx) { struct spu *spu = NULL; @@ -428,6 +363,51 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) return -ERESTARTSYS; } +/** + * grab_runnable_context - try to find a runnable context + * + * Remove the highest priority context on the runqueue and return it + * to the caller. Returns %NULL if no runnable context was found. + */ +static struct spu_context *grab_runnable_context(int prio) +{ + struct spu_context *ctx = NULL; + int best; + + spin_lock(&spu_prio->runq_lock); + best = sched_find_first_bit(spu_prio->bitmap); + if (best < prio) { + struct list_head *rq = &spu_prio->runq[best]; + + BUG_ON(list_empty(rq)); + + ctx = list_entry(rq->next, struct spu_context, rq); + __spu_del_from_rq(ctx); + } + spin_unlock(&spu_prio->runq_lock); + + return ctx; +} + +static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) +{ + struct spu *spu = ctx->spu; + struct spu_context *new = NULL; + + if (spu) { + new = grab_runnable_context(max_prio); + if (new || force) { + spu_unbind_context(spu, ctx); + spu_free(spu); + if (new) + wake_up(&new->stop_wq); + } + + } + + return new != NULL; +} + /** * spu_deactivate - unbind a context from it's physical spu * @ctx: spu context to unbind @@ -437,12 +417,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) */ void spu_deactivate(struct spu_context *ctx) { - struct spu *spu = ctx->spu; - - if (spu) { - spu_unbind_context(spu, ctx); - spu_reschedule(spu); - } + __spu_deactivate(ctx, 1, MAX_PRIO); } /** @@ -455,18 +430,38 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { - struct spu *spu; + mutex_lock(&ctx->state_mutex); + __spu_deactivate(ctx, 0, MAX_PRIO); + mutex_unlock(&ctx->state_mutex); +} - if (mutex_trylock(&ctx->state_mutex)) { - if ((spu = ctx->spu) != NULL) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - pr_debug("%s: yielding SPU %d NODE %d\n", - __FUNCTION__, spu->number, spu->node); - spu_deactivate(ctx); - } - } - mutex_unlock(&ctx->state_mutex); +void spu_sched_tick(struct work_struct *work) +{ + struct spu_context *ctx = + container_of(work, struct spu_context, sched_work.work); + int preempted; + + /* + * If this context is being stopped avoid rescheduling from the + * scheduler tick because we would block on the state_mutex. + * The caller will yield the spu later on anyway. + */ + if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) + return; + + mutex_lock(&ctx->state_mutex); + preempted = __spu_deactivate(ctx, 0, ctx->prio + 1); + mutex_unlock(&ctx->state_mutex); + + if (preempted) { + /* + * We need to break out of the wait loop in spu_run manually + * to ensure this context gets put on the runqueue again + * ASAP. + */ + wake_up(&ctx->stop_wq); + } else { + spu_start_tick(ctx); } } -- cgit v1.2.3 From e7c40012b84f670ba57fe4a3f453ddecc8813e9b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 5 Jun 2007 04:14:39 +1000 Subject: [POWERPC] Fix pci_setup_phb_io_dynamic for pci_iomap We had a problem on a system with only dynamically allocated PCI buses (using of_pci_phb_driver) in combination with libata. This setup ended up having no "primary" phb, which means that pci_io_base never got initialized and all IO port numbers are 64 bit numbers, which is larger than the PIO_MASK limit. Signed-off-by: Arnd Bergmann Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/of_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index d501c23e515..d454f61c9c7 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -433,7 +433,7 @@ static int __devinit of_pci_phb_probe(struct of_device *dev, * Note also that we don't do ISA, this will also be fixed with a * more massive rework. */ - pci_setup_phb_io(phb, 0); + pci_setup_phb_io(phb, pci_io_base == 0); /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); -- cgit v1.2.3 From 1552cb923efcd0f5499104256010d2ace437581d Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Tue, 5 Jun 2007 04:14:40 +1000 Subject: [POWERPC] cbe_cpufreq: Limit frequency via cpufreq notifier chain ... and get rid of cpufreq_set_policy call that caused a build failure due interfering commits. Signed-off-by: Thomas Renninger Signed-off-by: Christian Krafft Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/cbe_cpufreq.c | 33 +++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index f9ac3fe3be9..ac445998d83 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -67,6 +67,7 @@ static u64 MIC_Slow_Next_Timer_table[] = { 0x00003FC000000000ull, }; +static unsigned int pmi_frequency_limit = 0; /* * hardware specific functions */ @@ -164,7 +165,6 @@ static int set_pmode(int cpu, unsigned int slow_mode) { static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) { - struct cpufreq_policy policy; u8 cpu; u8 cbe_pmode_new; @@ -173,15 +173,27 @@ static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) cpu = cbe_node_to_cpu(pmi_msg.data1); cbe_pmode_new = pmi_msg.data2; - cpufreq_get_policy(&policy, cpu); + pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency; - policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency); - policy.min = min(policy.min, policy.max); + pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit); +} + +static int pmi_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct cpufreq_policy *policy = data; - pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max); - cpufreq_set_policy(&policy); + if (event != CPUFREQ_INCOMPATIBLE) + return 0; + + cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit); + return 0; } +static struct notifier_block pmi_notifier_block = { + .notifier_call = pmi_notifier, +}; + static struct pmi_handler cbe_pmi_handler = { .type = PMI_TYPE_FREQ_CHANGE, .handle_pmi_message = cbe_cpufreq_handle_pmi, @@ -238,12 +250,21 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); + if (pmi_dev) { + /* frequency might get limited later, initialize limit with max_freq */ + pmi_frequency_limit = max_freq; + cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + } + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) { + if (pmi_dev) + cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + cpufreq_frequency_table_put_attr(policy->cpu); return 0; } -- cgit v1.2.3 From 6dcbf164dcf4042bcbe9f56d94f65acd10b0e1f6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 5 Jun 2007 04:14:41 +1000 Subject: [POWERPC] scc_sio: Fix link failure scc_sio.o should only be built if the txx9 serial driver is actually built into the kernel. Signed-off-by: Christoph Hellwig Signed-off-by: Arnd Bergmann -- Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/celleb/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index f4f82520dc4..5240046d867 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -4,5 +4,5 @@ obj-y += interrupt.o iommu.o setup.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o +obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o obj-$(CONFIG_SPU_BASE) += spu_priv1.o -- cgit v1.2.3 From d30ac1242bf842fe28501a78a460a43910ef2dba Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Tue, 5 Jun 2007 07:16:15 +1000 Subject: [POWERPC] Fix typo in booting-without-of-txt section numbering Fix typo in section numbering. Signed-off-by: Stuart Yoder Acked-by: David Gibson Signed-off-by: Paul Mackerras --- Documentation/powerpc/booting-without-of.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index b49ce169a63..258a2797148 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1687,7 +1687,7 @@ platforms are moved over to use the flattened-device-tree model. }; }; - g) Flash chip nodes + j) Flash chip nodes Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. -- cgit v1.2.3 From e5c0b9ec538a86433ddd725f675e0a5a2117b9ed Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 5 Jun 2007 11:25:59 +1000 Subject: [POWERPC] spufs: Don't yield nosched context Nosched context sould never be scheduled out, thus we must not deactivate them in spu_yield ever. Signed-off-by: Christoph Hellwig Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/sched.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 68fcdc4515a..3b831e07f1e 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -430,9 +430,11 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { - mutex_lock(&ctx->state_mutex); - __spu_deactivate(ctx, 0, MAX_PRIO); - mutex_unlock(&ctx->state_mutex); + if (!(ctx->flags & SPU_CREATE_NOSCHED)) { + mutex_lock(&ctx->state_mutex); + __spu_deactivate(ctx, 0, MAX_PRIO); + mutex_unlock(&ctx->state_mutex); + } } void spu_sched_tick(struct work_struct *work) -- cgit v1.2.3 From 5e1e9ba690a2e2135a8f997242f9c46d2b8ac033 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Wed, 6 Jun 2007 04:29:14 +1000 Subject: [POWERPC] Add table of contents to booting-without-of.txt Add table of contents. Signed-off-by: Stuart Yoder Signed-off-by: Paul Mackerras --- Documentation/powerpc/booting-without-of.txt | 57 +++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index 258a2797148..d42d98107d4 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -1,7 +1,6 @@ Booting the Linux/ppc kernel without Open Firmware -------------------------------------------------- - (c) 2005 Benjamin Herrenschmidt , IBM Corp. (c) 2005 Becky Bruce , @@ -9,6 +8,62 @@ (c) 2006 MontaVista Software, Inc. Flash chip node definition +Table of Contents +================= + + I - Introduction + 1) Entry point for arch/powerpc + 2) Board support + + II - The DT block format + 1) Header + 2) Device tree generalities + 3) Device tree "structure" block + 4) Device tree "strings" block + + III - Required content of the device tree + 1) Note about cells and address representation + 2) Note about "compatible" properties + 3) Note about "name" properties + 4) Note about node and property names and character set + 5) Required nodes and properties + a) The root node + b) The /cpus node + c) The /cpus/* nodes + d) the /memory node(s) + e) The /chosen node + f) the /soc node + + IV - "dtc", the device tree compiler + + V - Recommendations for a bootloader + + VI - System-on-a-chip devices and nodes + 1) Defining child nodes of an SOC + 2) Representing devices without a current OF specification + a) MDIO IO device + c) PHY nodes + b) Gianfar-compatible ethernet nodes + d) Interrupt controllers + e) I2C + f) Freescale SOC USB controllers + g) Freescale SOC SEC Security Engines + h) Board Control and Status (BCSR) + i) Freescale QUICC Engine module (QE) + g) Flash chip nodes + + VII - Specifying interrupt information for devices + 1) interrupts property + 2) interrupt-parent property + 3) OpenPIC Interrupt Controllers + 4) ISA Interrupt Controllers + + Appendix A - Sample SOC node for MPC8540 + + +Revision Information +==================== + May 18, 2005: Rev 0.1 - Initial draft, no chapter III yet. May 19, 2005: Rev 0.2 - Add chapter III and bits & pieces here or -- cgit v1.2.3 From 87873c86802ba7ff9d9550d06459a6e99d72c5eb Mon Sep 17 00:00:00 2001 From: Sebastian Siewior Date: Wed, 6 Jun 2007 14:03:58 +1000 Subject: [POWERPC] spufs: Fix error handling in spufs_fill_dir() The error path in spufs_fill_dir() is broken. If d_alloc_name() or spufs_new_file() fails, spufs_prune_dir() is getting called. At this time dir->inode is not set and a NULL pointer is dereferenced by mutex_lock(). This bugfix replaces spufs_prune_dir() with a shorter version that does not touch dir->inode but simply removes all children. Signed-off-by: Sebastian Siewior Signed-off-by: Jeremy Kerr Acked-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 08356813977..9807206e021 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -177,7 +177,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir) static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, int mode, struct spu_context *ctx) { - struct dentry *dentry; + struct dentry *dentry, *tmp; int ret; while (files->name && files->name[0]) { @@ -193,7 +193,20 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, } return 0; out: - spufs_prune_dir(dir); + /* + * remove all children from dir. dir->inode is not set so don't + * just simply use spufs_prune_dir() and panic afterwards :) + * dput() looks like it will do the right thing: + * - dec parent's ref counter + * - remove child from parent's child list + * - free child's inode if possible + * - free child + */ + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { + dput(dentry); + } + + shrink_dcache_parent(dir); return ret; } -- cgit v1.2.3 From f40e524eaec9697d1515564fd5b961d839d2dc4f Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 7 Jun 2007 22:21:31 +1000 Subject: [POWERPC] Fix building of COFF zImages The COFF zImage (for booting oldworld powermacs) wasn't being built correctly because the procedure descriptor in crt0.S for the zImage entry point wasn't declared as .globl, and therefore wasn't getting pulled in from wrapper.a by the linker. This adds the necessary .globl statement. Signed-off-by: Paul Mackerras --- arch/powerpc/boot/crt0.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 5a4215c4b01..f1c4dfc635b 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -13,6 +13,7 @@ .text /* a procedure descriptor used when booting this as a COFF file */ + .globl _zimage_start_opd _zimage_start_opd: .long _zimage_start, 0, 0, 0 -- cgit v1.2.3