From b74a7e50cc87dea1b86d35860ace81412cb49886 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 30 Jan 2008 12:46:19 -0600 Subject: [POWERPC] 83xx: configure USB clock for MPC8315E SCCR USB bits are in a different location on the mpc8315. Signed-off-by: Jerry Huang Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8315erdb.dts | 2 +- arch/powerpc/platforms/83xx/mpc83xx.h | 2 ++ arch/powerpc/platforms/83xx/usb.c | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index b582032ba3d6..d7a1ececa30f 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -96,7 +96,7 @@ #address-cells = <1>; #size-cells = <1>; device_type = "soc"; - compatible = "simple-bus"; + compatible = "fsl,mpc8315-immr", "simple-bus"; ranges = <0 0xe0000000 0x00100000>; reg = <0xe0000000 0x00000200>; bus-frequency = <0>; diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 88bb748aff0d..68065e62fc3d 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h @@ -14,6 +14,8 @@ #define MPC83XX_SCCR_USB_DRCM_11 0x00300000 #define MPC83XX_SCCR_USB_DRCM_01 0x00100000 #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 +#define MPC8315_SCCR_USB_MASK 0x00c00000 +#define MPC8315_SCCR_USB_DRCM_11 0x00c00000 #define MPC837X_SCCR_USB_DRCM_11 0x00c00000 /* system i/o configuration register low */ diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index 681230a30acd..471fdd8f4108 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c @@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void) u32 temp; void __iomem *immap, *usb_regs; struct device_node *np = NULL; + struct device_node *immr_node = NULL; const void *prop; struct resource res; int ret = 0; @@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void) } /* Configure clock */ - temp = in_be32(immap + MPC83XX_SCCR_OFFS); - temp &= ~MPC83XX_SCCR_USB_MASK; - temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ - out_be32(immap + MPC83XX_SCCR_OFFS, temp); + immr_node = of_get_parent(np); + if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) + clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, + MPC8315_SCCR_USB_MASK, + MPC8315_SCCR_USB_DRCM_11); + else + clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, + MPC83XX_SCCR_USB_MASK, + MPC83XX_SCCR_USB_DRCM_11); /* Configure pin mux for ULPI. There is no pin mux for UTMI */ if (prop && !strcmp(prop, "ulpi")) { @@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void) iounmap(immap); + if (immr_node) + of_node_put(immr_node); + /* Map USB SOC space */ ret = of_address_to_resource(np, 0, &res); if (ret) { -- cgit v1.2.2 From 038200cfdc6467fa8100c5b9c3b81730f0158370 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 11 Jan 2008 15:03:26 +1100 Subject: [POWERPC] spufs: Add marker-based tracing facility This adds markers two important points in the spufs code and a new module (sputrace.ko) that allows reading these out through a proc file. Long-term I'd rather see something like lttng extended to use the spufs instrumentation, but for now I think this is a good enough quick solution. We'll probably want to add various addition event in addition to that ones I have already. Signed-off-by: Christoph Hellwig Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/Kconfig | 7 + arch/powerpc/platforms/cell/spufs/Makefile | 2 + arch/powerpc/platforms/cell/spufs/file.c | 6 + arch/powerpc/platforms/cell/spufs/sched.c | 28 ++- arch/powerpc/platforms/cell/spufs/spufs.h | 5 + arch/powerpc/platforms/cell/spufs/sputrace.c | 250 +++++++++++++++++++++++++++ 6 files changed, 291 insertions(+), 7 deletions(-) create mode 100644 arch/powerpc/platforms/cell/spufs/sputrace.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 3a963b4a9be0..2f169991896d 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -54,6 +54,13 @@ config SPU_FS_64K_LS uses 4K pages. This can improve performances of applications using multiple SPEs by lowering the TLB pressure on them. +config SPU_TRACE + tristate "SPU event tracing support" + depends on SPU_FS && MARKERS + help + This option allows reading a trace of spu-related events through + the sputrace file in procfs. + config SPU_BASE bool default n diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index d3a349fb42e5..99610a6361f2 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile @@ -4,6 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o spufs-y += switch.o fault.o lscsa_alloc.o +obj-$(CONFIG_SPU_TRACE) += sputrace.o + # Rules to build switch.o with the help of SPU tool chain SPU_CROSS := spu- SPU_CC := $(SPU_CROSS)gcc diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 3fcd06418b01..1018acd1746b 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -358,6 +359,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, struct spu_context *ctx = vma->vm_file->private_data; unsigned long area, offset = address - vma->vm_start; + spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx); + offset += vma->vm_pgoff << PAGE_SHIFT; if (offset >= ps_size) return NOPFN_SIGBUS; @@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, if (ctx->state == SPU_STATE_SAVED) { up_read(¤t->mm->mmap_sem); + spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx); spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); + spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu); down_read(¤t->mm->mmap_sem); } else { area = ctx->spu->problem_phys + ps_offs; vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); + spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu); } spu_release(ctx); diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 00d914232af1..5915343e2599 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -216,8 +217,8 @@ void do_notify_spus_active(void) */ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, - spu->number, spu->node); + spu_context_trace(spu_bind_context__enter, ctx, spu); + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); if (ctx->flags & SPU_CREATE_NOSCHED) @@ -399,8 +400,8 @@ static int has_affinity(struct spu_context *ctx) */ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) { - pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, - spu->pid, spu->number, spu->node); + spu_context_trace(spu_unbind_context__enter, ctx, spu); + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); if (spu->ctx->flags & SPU_CREATE_NOSCHED) @@ -528,6 +529,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx) struct spu *spu, *aff_ref_spu; int node, n; + spu_context_nospu_trace(spu_get_idle__enter, ctx); + if (ctx->gang) { mutex_lock(&ctx->gang->aff_mutex); if (has_affinity(ctx)) { @@ -546,8 +549,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx) if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) ctx->gang->aff_ref_spu = NULL; mutex_unlock(&ctx->gang->aff_mutex); - - return NULL; + goto not_found; } mutex_unlock(&ctx->gang->aff_mutex); } @@ -565,12 +567,14 @@ static struct spu *spu_get_idle(struct spu_context *ctx) mutex_unlock(&cbe_spu_info[node].list_mutex); } + not_found: + spu_context_nospu_trace(spu_get_idle__not_found, ctx); return NULL; found: spu->alloc_state = SPU_USED; mutex_unlock(&cbe_spu_info[node].list_mutex); - pr_debug("Got SPU %d %d\n", spu->number, spu->node); + spu_context_trace(spu_get_idle__found, ctx, spu); spu_init_channels(spu); return spu; } @@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx) struct spu *spu; int node, n; + spu_context_nospu_trace(spu_find_vitim__enter, ctx); + /* * Look for a possible preemption candidate on the local node first. * If there is no candidate look at the other nodes. This isn't @@ -640,6 +646,8 @@ static struct spu *find_victim(struct spu_context *ctx) goto restart; } + spu_context_trace(__spu_deactivate__unload, ctx, spu); + mutex_lock(&cbe_spu_info[node].list_mutex); cbe_spu_info[node].nr_active--; spu_unbind_context(spu, victim); @@ -822,6 +830,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) */ void spu_deactivate(struct spu_context *ctx) { + spu_context_nospu_trace(spu_deactivate__enter, ctx); __spu_deactivate(ctx, 1, MAX_PRIO); } @@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { + spu_context_nospu_trace(spu_yield__enter, ctx); if (!(ctx->flags & SPU_CREATE_NOSCHED)) { mutex_lock(&ctx->state_mutex); __spu_deactivate(ctx, 0, MAX_PRIO); @@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx) goto out; spu = ctx->spu; + + spu_context_trace(spusched_tick__preempt, ctx, spu); + new = grab_runnable_context(ctx->prio + 1, spu->node); if (new) { spu_unschedule(spu, ctx); spu_add_to_rq(ctx); } else { + spu_context_nospu_trace(spusched_tick__newslice, ctx); ctx->time_slice++; } out: diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 0e114038ea6f..795a1b52538b 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa); extern void spuctx_switch_state(struct spu_context *ctx, enum spu_utilization_state new_state); +#define spu_context_trace(name, ctx, spu) \ + trace_mark(name, "%p %p", ctx, spu); +#define spu_context_nospu_trace(name, ctx) \ + trace_mark(name, "%p", ctx); + #endif diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c new file mode 100644 index 000000000000..2b1953f6f12e --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/sputrace.c @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2007 IBM Deutschland Entwicklung GmbH + * Released under GPL v2. + * + * Partially based on net/ipv4/tcp_probe.c. + * + * Simple tracing facility for spu contexts. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "spufs.h" + +struct spu_probe { + const char *name; + const char *format; + marker_probe_func *probe_func; +}; + +struct sputrace { + ktime_t tstamp; + int owner_tid; /* owner */ + int curr_tid; + const char *name; + int number; +}; + +static int bufsize __read_mostly = 16384; +MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)"); +module_param(bufsize, int, 0); + + +static DEFINE_SPINLOCK(sputrace_lock); +static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait); +static ktime_t sputrace_start; +static unsigned long sputrace_head, sputrace_tail; +static struct sputrace *sputrace_log; + +static int sputrace_used(void) +{ + return (sputrace_head - sputrace_tail) % bufsize; +} + +static inline int sputrace_avail(void) +{ + return bufsize - sputrace_used(); +} + +static int sputrace_sprint(char *tbuf, int n) +{ + const struct sputrace *t = sputrace_log + sputrace_tail % bufsize; + struct timespec tv = + ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start)); + + return snprintf(tbuf, n, + "[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n", + (unsigned long) tv.tv_sec, + (unsigned long) tv.tv_nsec, + t->owner_tid, + t->name, + t->curr_tid, + t->number); +} + +static ssize_t sputrace_read(struct file *file, char __user *buf, + size_t len, loff_t *ppos) +{ + int error = 0, cnt = 0; + + if (!buf || len < 0) + return -EINVAL; + + while (cnt < len) { + char tbuf[128]; + int width; + + error = wait_event_interruptible(sputrace_wait, + sputrace_used() > 0); + if (error) + break; + + spin_lock(&sputrace_lock); + if (sputrace_head == sputrace_tail) { + spin_unlock(&sputrace_lock); + continue; + } + + width = sputrace_sprint(tbuf, sizeof(tbuf)); + if (width < len) + sputrace_tail = (sputrace_tail + 1) % bufsize; + spin_unlock(&sputrace_lock); + + if (width >= len) + break; + + error = copy_to_user(buf + cnt, tbuf, width); + if (error) + break; + cnt += width; + } + + return cnt == 0 ? error : cnt; +} + +static int sputrace_open(struct inode *inode, struct file *file) +{ + spin_lock(&sputrace_lock); + sputrace_head = sputrace_tail = 0; + sputrace_start = ktime_get(); + spin_unlock(&sputrace_lock); + + return 0; +} + +static const struct file_operations sputrace_fops = { + .owner = THIS_MODULE, + .open = sputrace_open, + .read = sputrace_read, +}; + +static void sputrace_log_item(const char *name, struct spu_context *ctx, + struct spu *spu) +{ + spin_lock(&sputrace_lock); + if (sputrace_avail() > 1) { + struct sputrace *t = sputrace_log + sputrace_head; + + t->tstamp = ktime_get(); + t->owner_tid = ctx->tid; + t->name = name; + t->curr_tid = current->pid; + t->number = spu ? spu->number : -1; + + sputrace_head = (sputrace_head + 1) % bufsize; + } else { + printk(KERN_WARNING + "sputrace: lost samples due to full buffer.\n"); + } + spin_unlock(&sputrace_lock); + + wake_up(&sputrace_wait); +} + +static void spu_context_event(const struct marker *mdata, + void *private, const char *format, ...) +{ + struct spu_probe *p = mdata->private; + va_list ap; + struct spu_context *ctx; + struct spu *spu; + + va_start(ap, format); + ctx = va_arg(ap, struct spu_context *); + spu = va_arg(ap, struct spu *); + + sputrace_log_item(p->name, ctx, spu); + va_end(ap); +} + +static void spu_context_nospu_event(const struct marker *mdata, + void *private, const char *format, ...) +{ + struct spu_probe *p = mdata->private; + va_list ap; + struct spu_context *ctx; + + va_start(ap, format); + ctx = va_arg(ap, struct spu_context *); + + sputrace_log_item(p->name, ctx, NULL); + va_end(ap); +} + +struct spu_probe spu_probes[] = { + { "spu_bind_context__enter", "%p %p", spu_context_event }, + { "spu_unbind_context__enter", "%p %p", spu_context_event }, + { "spu_get_idle__enter", "%p", spu_context_nospu_event }, + { "spu_get_idle__found", "%p %p", spu_context_event }, + { "spu_get_idle__not_found", "%p", spu_context_nospu_event }, + { "spu_find_victim__enter", "%p", spu_context_nospu_event }, + { "spusched_tick__preempt", "%p %p", spu_context_event }, + { "spusched_tick__newslice", "%p", spu_context_nospu_event }, + { "spu_yield__enter", "%p", spu_context_nospu_event }, + { "spu_deactivate__enter", "%p", spu_context_nospu_event }, + { "__spu_deactivate__unload", "%p %p", spu_context_event }, + { "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event }, + { "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event }, + { "spufs_ps_nopfn__wake", "%p %p", spu_context_event }, + { "spufs_ps_nopfn__insert", "%p %p", spu_context_event }, + { "spu_acquire_saved__enter", "%p", spu_context_nospu_event }, + { "destroy_spu_context__enter", "%p", spu_context_nospu_event }, +}; + +static int __init sputrace_init(void) +{ + struct proc_dir_entry *entry; + int i, error = -ENOMEM; + + sputrace_log = kcalloc(sizeof(struct sputrace), + bufsize, GFP_KERNEL); + if (!sputrace_log) + goto out; + + entry = create_proc_entry("sputrace", S_IRUSR, NULL); + if (!entry) + goto out_free_log; + entry->proc_fops = &sputrace_fops; + + for (i = 0; i < ARRAY_SIZE(spu_probes); i++) { + struct spu_probe *p = &spu_probes[i]; + + error = marker_probe_register(p->name, p->format, + p->probe_func, p); + if (error) + printk(KERN_INFO "Unable to register probe %s\n", + p->name); + + error = marker_arm(p->name); + if (error) + printk(KERN_INFO "Unable to arm probe %s\n", p->name); + } + + return 0; + +out_free_log: + kfree(sputrace_log); +out: + return -ENOMEM; +} + +static void __exit sputrace_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(spu_probes); i++) + marker_probe_unregister(spu_probes[i].name); + + remove_proc_entry("sputrace", NULL); + kfree(sputrace_log); +} + +module_init(sputrace_init); +module_exit(sputrace_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 60cf54db47727935af1c439f59c636a96a8cbd4b Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 11 Jan 2008 15:03:26 +1100 Subject: [POWERPC] spufs: Fix SPE single-step mode Currently we only catch debug events through the 0x3fff status; spufs_run_spu doesn't handle single-step SPE events. This change adds a handler for conditions where the SPE is stopped due to single-step-mode. Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/run.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index c01a09da1e56..b4814c740d8a 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -410,8 +410,11 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) * since we have TIF_SINGLESTEP set, thus the kernel will do * it upon return from the syscall anyawy */ - if ((status & SPU_STATUS_STOPPED_BY_STOP) - && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + if (unlikely(status & SPU_STATUS_SINGLE_STEP)) + ret = -ERESTARTSYS; + + else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP) + && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) { force_sig(SIGTRAP, current); ret = -ERESTARTSYS; } -- cgit v1.2.2 From 58119068cb27ef7513f80aff44b62a3a8f40ef5f Mon Sep 17 00:00:00 2001 From: Andre Detsch Date: Fri, 11 Jan 2008 15:03:26 +1100 Subject: [POWERPC] spufs: Fix memory leak on SPU affinity Reference count for the "neighbor" spu context was not being correctly decremented after usage. So, contexts used as reference during SPU affinity setup were not being deallocated, leading to a memory leak. Signed-off-by: Andre Detsch Signed-off-by: Jeremy Kerr Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/inode.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index c0e968a4c211..90784c029f25 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -322,7 +322,7 @@ static struct spu_context * spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, struct file *filp) { - struct spu_context *tmp, *neighbor; + struct spu_context *tmp, *neighbor, *err; int count, node; int aff_supp; @@ -354,11 +354,15 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && !list_entry(neighbor->aff_list.next, struct spu_context, - aff_list)->aff_head) - return ERR_PTR(-EEXIST); + aff_list)->aff_head) { + err = ERR_PTR(-EEXIST); + goto out_put_neighbor; + } - if (gang != neighbor->gang) - return ERR_PTR(-EINVAL); + if (gang != neighbor->gang) { + err = ERR_PTR(-EINVAL); + goto out_put_neighbor; + } count = 1; list_for_each_entry(tmp, &gang->aff_list_head, aff_list) @@ -372,11 +376,17 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, break; } - if (node == MAX_NUMNODES) - return ERR_PTR(-EEXIST); + if (node == MAX_NUMNODES) { + err = ERR_PTR(-EEXIST); + goto out_put_neighbor; + } } return neighbor; + +out_put_neighbor: + put_spu_context(neighbor); + return err; } static void @@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry, if (ret) goto out_aff_unlock; - if (affinity) + if (affinity) { spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx, neighbor); + if (neighbor) + put_spu_context(neighbor); + } /* * get references for dget and mntget, will be released -- cgit v1.2.2 From b277b02588ec7534a033ff1cb0f947c18a4d3b54 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 31 Jan 2008 12:56:58 -0600 Subject: [POWERPC] 83xx: Correct 2nd PCI controller interrupt value in mpc834x_mds dts According to the 8349EA ref man, the second PCI PHB IRQ is 67. Thanks to Peter Van Ackeren for finding this. Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc834x_mds.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index 7480edae85ed..0199c5c548d8 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -332,7 +332,7 @@ 0xc000 0x0 0x0 0x3 &ipic 23 0x8 0xc000 0x0 0x0 0x4 &ipic 20 0x8>; interrupt-parent = <&ipic>; - interrupts = <66 0x8>; + interrupts = <67 0x8>; bus-range = <0 0>; ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000 0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 -- cgit v1.2.2 From 266fb4af93427923ee76bd9dc73ec352b8d791ab Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Thu, 31 Jan 2008 11:36:56 -0600 Subject: [POWERPC] 8xx: adder875, ep88xc: fix to match recent 8xx cleanups. asm/commproc.h was renamed to asm/cpm1.h sysdev/commproc.h was renamed to platforms/8xx/mpc8xx.h m8xx_pic_init was renamed to mpc8xx_pics_init Signed-off-by: Scott Wood Signed-off-by: Kumar Gala --- arch/powerpc/platforms/8xx/adder875.c | 6 +++--- arch/powerpc/platforms/8xx/ep88xc.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/8xx/adder875.c b/arch/powerpc/platforms/8xx/adder875.c index c6bc0783c3b0..82363e98f50e 100644 --- a/arch/powerpc/platforms/8xx/adder875.c +++ b/arch/powerpc/platforms/8xx/adder875.c @@ -15,12 +15,12 @@ #include #include -#include +#include #include #include #include -#include +#include "mpc8xx.h" struct cpm_pin { int port, pin, flags; @@ -108,7 +108,7 @@ define_machine(adder875) { .name = "Adder MPC875", .probe = adder875_probe, .setup_arch = adder875_setup, - .init_IRQ = m8xx_pic_init, + .init_IRQ = mpc8xx_pics_init, .get_irq = mpc8xx_get_irq, .restart = mpc8xx_restart, .calibrate_decr = generic_calibrate_decr, diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c index a8dffa005775..7d9ac6040d63 100644 --- a/arch/powerpc/platforms/8xx/ep88xc.c +++ b/arch/powerpc/platforms/8xx/ep88xc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "mpc8xx.h" -- cgit v1.2.2 From bb125fb0e09c1b1e17d0b616f0e31fea937af9f6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 25 Jan 2008 16:59:12 +1100 Subject: [POWERPC] Search for and publish cell OF platform devices earlier Currently cell publishes OF devices at device_initcall() time, which means the earliest a driver can bind to a device is also device_initcall() time. We have a driver we want to register before other devices, so publish the devices at subsys_initcall() time. This should not cause any behaviour change for existing drivers, as they are still bound at device_initcall() time. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index e6534b519c9a..a7f609b3b876 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -98,7 +98,7 @@ static int __init cell_publish_devices(void) } return 0; } -machine_device_initcall(cell, cell_publish_devices); +machine_subsys_initcall(cell, cell_publish_devices); static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) { -- cgit v1.2.2 From e4347dfb580e0172185cb38529266ecf3b4d0baa Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 25 Jan 2008 16:59:14 +1100 Subject: [POWERPC] Convert axon_msi to an of_platform driver Now that we create of_platform devices earlier on cell, we can make the axon_msi driver an of_platform driver. This makes the code cleaner in several ways, and most importantly means we have a struct device. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/axon_msi.c | 76 +++++++++++++++------------------- 1 file changed, 34 insertions(+), 42 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index 095988f13bf4..ea3dc8c64a38 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include @@ -67,12 +67,9 @@ struct axon_msic { struct irq_host *irq_host; __le32 *fifo; dcr_host_t dcr_host; - struct list_head list; u32 read_offset; }; -static LIST_HEAD(axon_msic_list); - static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) { pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); @@ -292,30 +289,25 @@ static struct irq_host_ops msic_host_ops = { .map = msic_host_map, }; -static int axon_msi_notify_reboot(struct notifier_block *nb, - unsigned long code, void *data) +static int axon_msi_shutdown(struct of_device *device) { - struct axon_msic *msic; + struct axon_msic *msic = device->dev.platform_data; u32 tmp; - list_for_each_entry(msic, &axon_msic_list, list) { - pr_debug("axon_msi: disabling %s\n", - msic->irq_host->of_node->full_name); - tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); - tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; - msic_dcr_write(msic, MSIC_CTRL_REG, tmp); - } + pr_debug("axon_msi: disabling %s\n", + msic->irq_host->of_node->full_name); + tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG); + tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; + msic_dcr_write(msic, MSIC_CTRL_REG, tmp); return 0; } -static struct notifier_block axon_msi_reboot_notifier = { - .notifier_call = axon_msi_notify_reboot -}; - -static int axon_msi_setup_one(struct device_node *dn) +static int axon_msi_probe(struct of_device *device, + const struct of_device_id *device_id) { struct page *page; + struct device_node *dn = device->node; struct axon_msic *msic; unsigned int virq; int dcr_base, dcr_len; @@ -385,7 +377,11 @@ static int axon_msi_setup_one(struct device_node *dn) MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE | MSIC_CTRL_FIFO_SIZE); - list_add(&msic->list, &axon_msic_list); + device->dev.platform_data = msic; + + ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; + ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; + ppc_md.msi_check_device = axon_msi_check_device; printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name); @@ -402,28 +398,24 @@ out: return -1; } -static int axon_msi_init(void) -{ - struct device_node *dn; - int found = 0; - - pr_debug("axon_msi: initialising ...\n"); - - for_each_compatible_node(dn, NULL, "ibm,axon-msic") { - if (axon_msi_setup_one(dn) == 0) - found++; - } - - if (found) { - ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; - ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; - ppc_md.msi_check_device = axon_msi_check_device; - - register_reboot_notifier(&axon_msi_reboot_notifier); +static const struct of_device_id axon_msi_device_id[] = { + { + .compatible = "ibm,axon-msic" + }, + {} +}; - pr_debug("axon_msi: registered callbacks!\n"); - } +static struct of_platform_driver axon_msi_driver = { + .match_table = axon_msi_device_id, + .probe = axon_msi_probe, + .shutdown = axon_msi_shutdown, + .driver = { + .name = "axon-msi" + }, +}; - return 0; +static int __init axon_msi_init(void) +{ + return of_register_platform_driver(&axon_msi_driver); } -arch_initcall(axon_msi_init); +subsys_initcall(axon_msi_init); -- cgit v1.2.2 From de4c928b843063b7079c35c950c1d38c559fa0cb Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 25 Jan 2008 16:59:14 +1100 Subject: [POWERPC] Avoid DMA exception when using axon_msi with IOMMU There's a brown-paper-bag bug in axon_msi, we pass the address of our FIFO directly to the hardware, without DMA mapping it. This leads to DMA exceptions if you enable MSI & the IOMMU. The fix is to correctly DMA map the fifo, dma_alloc_coherent() does what we want - and we need to track the virt & phys addresses. Signed-off-by: Michael Ellerman Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/axon_msi.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index ea3dc8c64a38..b9a97c4ae15a 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -65,7 +65,8 @@ struct axon_msic { struct irq_host *irq_host; - __le32 *fifo; + __le32 *fifo_virt; + dma_addr_t fifo_phys; dcr_host_t dcr_host; u32 read_offset; }; @@ -91,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) while (msic->read_offset != write_offset) { idx = msic->read_offset / sizeof(__le32); - msi = le32_to_cpu(msic->fifo[idx]); + msi = le32_to_cpu(msic->fifo_virt[idx]); msi &= 0xFFFF; pr_debug("axon_msi: woff %x roff %x msi %x\n", @@ -306,7 +307,6 @@ static int axon_msi_shutdown(struct of_device *device) static int axon_msi_probe(struct of_device *device, const struct of_device_id *device_id) { - struct page *page; struct device_node *dn = device->node; struct axon_msic *msic; unsigned int virq; @@ -338,16 +338,14 @@ static int axon_msi_probe(struct of_device *device, goto out_free_msic; } - page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL, - get_order(MSIC_FIFO_SIZE_BYTES)); - if (!page) { + msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, + &msic->fifo_phys, GFP_KERNEL); + if (!msic->fifo_virt) { printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n", dn->full_name); goto out_free_msic; } - msic->fifo = page_address(page); - msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP, NR_IRQS, &msic_host_ops, 0); if (!msic->irq_host) { @@ -370,9 +368,9 @@ static int axon_msi_probe(struct of_device *device, pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); /* Enable the MSIC hardware */ - msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32); + msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32); msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG, - (u64)msic->fifo & 0xFFFFFFFF); + msic->fifo_phys & 0xFFFFFFFF); msic_dcr_write(msic, MSIC_CTRL_REG, MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE | MSIC_CTRL_FIFO_SIZE); @@ -390,7 +388,8 @@ static int axon_msi_probe(struct of_device *device, out_free_host: kfree(msic->irq_host); out_free_fifo: - __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES)); + dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt, + msic->fifo_phys); out_free_msic: kfree(msic); out: -- cgit v1.2.2 From c6d01179bfee3048cce98fe303d7265faa3861a7 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 5 Feb 2008 13:13:15 +1100 Subject: [POWERPC] Avoid possible extra of_node_put in axon_msi.c I got this warning from gcc: arch/powerpc/platforms/cell/axon_msi.c:118: warning: 'tmp' may be used uninitialized in this function Which turns out to be a false positive, but pointed out that it was possible for the error path in find_msi_translator() to do an extra of_node_put on a node. This fixes it by localising the ref counting a bit. As a side effect, the warning goes away. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/axon_msi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index b9a97c4ae15a..d95e71dee91f 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -137,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) tmp = dn; dn = of_find_node_by_phandle(*ph); + of_node_put(tmp); if (!dn) { dev_dbg(&dev->dev, "axon_msi: msi-translator doesn't point to a node\n"); @@ -154,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev) out_error: of_node_put(dn); - of_node_put(tmp); return msic; } -- cgit v1.2.2 From de7d812d05f3075096a3e37222f4e1876ae25e6c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 5 Feb 2008 14:15:12 +1100 Subject: [POWERPC] iSeries: Fix section mismatch in viodsasd WARNING: vmlinux.o(.text+0x3017c): Section mismatch in reference from the function .vio_create_viodasd() to the function .devinit.text:.vio_register_device_node() Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index f0bad7070fb5..f98867252ee2 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev) * Returns a pointer to the created vio_dev or NULL if node has * NULL device_type or compatible fields. */ -struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) +struct vio_dev *vio_register_device_node(struct device_node *of_node) { struct vio_dev *viodev; const unsigned int *unit_address; -- cgit v1.2.2 From ad7f71674ad7c3c4467e48f6ab9e85516dae2720 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 5 Feb 2008 16:16:48 +1100 Subject: [POWERPC] Use a sensible default for clock_getres() in the VDSO This ensures that the syscall and the (fast) vdso versions of clock_getres() will return the same resolution. Signed-off-by: Tony Breeds Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/asm-offsets.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ed083feaf6f9..e6e49289f788 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #include @@ -312,7 +313,7 @@ int main(void) DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - DEFINE(CLOCK_REALTIME_RES, TICK_NSEC); + DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64); #ifdef CONFIG_BUG DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); -- cgit v1.2.2 From f5903ede0015db5b53458092b6ae2af074fa49d4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 5 Feb 2008 23:01:50 +1100 Subject: [POWERPC] Fix legacy serial search for opb bus ports The patch to legacy_serial.c (1a7507c7da2df6856e085e0fbb0c9ea8c12ac4e, Reduce code duplication in legacy_serial, add UART parent types) changed the semantics for opb ports from type = "opb" || compatible = "ibm,opb" to type = "opb" && compatible = "ibm,opb". The result is serial ports on our QS21s (Cell blades) don't get found, and for some reason the machine doesn't boot at all - possibly it's panicking due to lack of a console? The fix is to add two entries to the of_device_id table, one that looks for type = "opb" and the other compatible = "ibm,opb". Signed-off-by: Michael Ellerman Acked-by: Paul Gortmaker Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/legacy_serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 76b862bd1fe9..61dd17449ddc 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -36,7 +36,8 @@ static struct legacy_serial_info { static struct __initdata of_device_id parents[] = { {.type = "soc",}, {.type = "tsi-bridge",}, - {.type = "opb", .compatible = "ibm,opb",}, + {.type = "opb", }, + {.compatible = "ibm,opb",}, {.compatible = "simple-bus",}, {.compatible = "wrs,epld-localbus",}, }; -- cgit v1.2.2 From 551ed332da2f52daf5d01fc76d2a894aba79d316 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 6 Feb 2008 06:43:26 +1100 Subject: [POWERPC] update_mmu_cache: Don't cache-flush non-readable pages Currently, update_mmu_cache will crash if given a no-access PTE. There's no need to synchronize dcache/icache unless it's an exec mapping -- however, due to the existence of older glibc versions that execute out of a read-but-no-exec page, readability is tested instead. This assumes no exec-only mappings; if such mappings become supported, they will need to go through the kmap_atomic() version of dcache/icache synchronization. This fixes a bug reported by some users where the kernel would crash while dumping core on a threaded program. Signed-off-by: Scott Wood Acked-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/mm/mem.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index e8122447f019..c7d7bd43a251 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -483,7 +483,12 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address, */ _tlbie(address, 0 /* 8xx doesn't care about PID */); #endif - if (!PageReserved(page) + /* The _PAGE_USER test should really be _PAGE_EXEC, but + * older glibc versions execute some code from no-exec + * pages, which for now we are supporting. If exec-only + * pages are ever implemented, this will have to change. + */ + if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER) && !test_bit(PG_arch_1, &page->flags)) { if (vma->vm_mm == current->active_mm) { __flush_dcache_icache((void *) address); -- cgit v1.2.2 From 5cfade1829440af45cd24ea7483d2e16876fc602 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Thu, 31 Jan 2008 19:40:05 -0600 Subject: [POWERPC] 83xx: Add rtc node to mpc8313erdb dts The 8313 rdb has a ds1339 at address 0x68. Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8313erdb.dts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index 2d6653fe72ff..e1f0dca8ac39 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -118,6 +118,10 @@ interrupts = <14 0x8>; interrupt-parent = <&ipic>; dfsrr; + rtc@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + }; }; i2c@3100 { -- cgit v1.2.2 From 03bbfe8b97eb277f1af27fef5a14224f7878a983 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Sun, 3 Feb 2008 23:21:29 +0000 Subject: [POWERPC] 8xx: Add clock-frequency to adder875 and mpc885ads dts cpm_uart_core has a dependency on fsl,cpm-brg/clock-frequency, this means that a .dts that uses the cpm uart driver needs to supply a clock-frequency entry for get_brgfreq to return a meaningful number. Signed-off-by: Bryan O'Donoghue Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/adder875-redboot.dts | 1 + arch/powerpc/boot/dts/adder875-uboot.dts | 1 + arch/powerpc/boot/dts/mpc885ads.dts | 1 + 3 files changed, 3 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/adder875-redboot.dts b/arch/powerpc/boot/dts/adder875-redboot.dts index 930bfb3894eb..28e9cd3d7a21 100644 --- a/arch/powerpc/boot/dts/adder875-redboot.dts +++ b/arch/powerpc/boot/dts/adder875-redboot.dts @@ -151,6 +151,7 @@ compatible = "fsl,mpc875-brg", "fsl,cpm1-brg", "fsl,cpm-brg"; + clock-frequency = <50000000>; reg = <0x9f0 0x10>; }; diff --git a/arch/powerpc/boot/dts/adder875-uboot.dts b/arch/powerpc/boot/dts/adder875-uboot.dts index 0197242dacfb..54fb60ec03e5 100644 --- a/arch/powerpc/boot/dts/adder875-uboot.dts +++ b/arch/powerpc/boot/dts/adder875-uboot.dts @@ -150,6 +150,7 @@ compatible = "fsl,mpc875-brg", "fsl,cpm1-brg", "fsl,cpm-brg"; + clock-frequency = <50000000>; reg = <0x9f0 0x10>; }; diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts index 8848e637293e..d84a012c2aaf 100644 --- a/arch/powerpc/boot/dts/mpc885ads.dts +++ b/arch/powerpc/boot/dts/mpc885ads.dts @@ -166,6 +166,7 @@ compatible = "fsl,mpc885-brg", "fsl,cpm1-brg", "fsl,cpm-brg"; + clock-frequency = <0>; reg = <9f0 10>; }; -- cgit v1.2.2 From 0367aad1ad5f8085ed15e9e30604f50108a1ea06 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Sat, 2 Feb 2008 13:02:51 -0600 Subject: [POWERPC] Fix storcenter DTS typos, feedback, IRQs. Cleaned up IRQ layout and removed unsused ISU allocations. Fixed RTC address typo from /dts-v1/ conversion. Incorporated list suggestions to use an "iomega," vendor prefix, and to use a node reference rather than a hard path. Signed-off-by: Jon Loeliger Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/storcenter.dts | 12 ++++++------ arch/powerpc/platforms/embedded6xx/storcenter.c | 25 +++++-------------------- 2 files changed, 11 insertions(+), 26 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/storcenter.dts b/arch/powerpc/boot/dts/storcenter.dts index 2204874ac5f3..5893816c0bce 100644 --- a/arch/powerpc/boot/dts/storcenter.dts +++ b/arch/powerpc/boot/dts/storcenter.dts @@ -15,7 +15,7 @@ / { model = "StorCenter"; - compatible = "storcenter"; + compatible = "iomega,storcenter"; #address-cells = <1>; #size-cells = <1>; @@ -62,12 +62,12 @@ #size-cells = <0>; compatible = "fsl-i2c"; reg = <0x3000 0x100>; - interrupts = <5 2>; + interrupts = <17 2>; interrupt-parent = <&mpic>; rtc@68 { compatible = "dallas,ds1337"; - reg = <68>; + reg = <0x68>; }; }; @@ -78,7 +78,7 @@ reg = <0x4500 0x20>; clock-frequency = <97553800>; /* Hz */ current-speed = <115200>; - interrupts = <9 2>; + interrupts = <25 2>; interrupt-parent = <&mpic>; }; @@ -89,7 +89,7 @@ reg = <0x4600 0x20>; clock-frequency = <97553800>; /* Hz */ current-speed = <9600>; - interrupts = <10 2>; + interrupts = <26 2>; interrupt-parent = <&mpic>; }; @@ -136,6 +136,6 @@ }; chosen { - linux,stdout-path = "/soc/serial@4500"; + linux,stdout-path = &serial0; }; }; diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index e12e9d298716..8864e4884980 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -132,33 +132,18 @@ static void __init storcenter_init_IRQ(void) paddr = (phys_addr_t)of_translate_address(dnp, prop); mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, - 4, 32, " EPIC "); + 16, 32, " OpenPIC "); of_node_put(dnp); BUG_ON(mpic == NULL); - /* PCI IRQs */ /* - * 2.6.12 patch: - * openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200); - * openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120); - * first_irq, num_irqs, __iomem first_ISR - * o_ss: i, src: 0, fdf50200 - * o_ss: i, src: 1, fdf50220 - * o_ss: i, src: 2, fdf50240 - * o_ss: i, src: 3, fdf50260 - * o_ss: i, src: 4, fdf50280 - * o_ss: i, src: 5, fdf51120 - * o_ss: i, src: 6, fdf51140 + * 16 Serial Interrupts followed by 16 Internal Interrupts. + * I2C is the second internal, so it is at 17, 0x11020. */ mpic_assign_isu(mpic, 0, paddr + 0x10200); - mpic_assign_isu(mpic, 1, paddr + 0x10220); - mpic_assign_isu(mpic, 2, paddr + 0x10240); - mpic_assign_isu(mpic, 3, paddr + 0x10260); - mpic_assign_isu(mpic, 4, paddr + 0x10280); - mpic_assign_isu(mpic, 5, paddr + 0x11120); - mpic_assign_isu(mpic, 6, paddr + 0x11140); + mpic_assign_isu(mpic, 1, paddr + 0x11000); mpic_init(mpic); } @@ -178,7 +163,7 @@ static int __init storcenter_probe(void) { unsigned long root = of_get_flat_dt_root(); - return of_flat_dt_is_compatible(root, "storcenter"); + return of_flat_dt_is_compatible(root, "iomega,storcenter"); } define_machine(storcenter){ -- cgit v1.2.2 From 39aef685af431c032ffd2763ec8782b13c32520c Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Mon, 4 Feb 2008 18:27:55 -0600 Subject: [POWERPC] Made FSL Book-E PMC support more generic Some of the more recent e300 cores have the same performance monitor implementation as the e500. e300 isn't book-e, so the name isn't really appropriate. In preparation for e300 support, rename a bunch of fsl_booke things to say fsl_emb (Freescale Embedded Performance Monitors). Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/kernel/cputable.c | 4 +- arch/powerpc/kernel/pmc.c | 2 +- arch/powerpc/oprofile/Makefile | 2 +- arch/powerpc/oprofile/common.c | 6 +- arch/powerpc/oprofile/op_model_fsl_booke.c | 371 ----------------------------- arch/powerpc/oprofile/op_model_fsl_emb.c | 369 ++++++++++++++++++++++++++++ arch/powerpc/platforms/Kconfig.cputype | 4 + 7 files changed, 380 insertions(+), 378 deletions(-) delete mode 100644 arch/powerpc/oprofile/op_model_fsl_booke.c create mode 100644 arch/powerpc/oprofile/op_model_fsl_emb.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index a4c2771b5e62..98a1c9e6b9fa 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1435,7 +1435,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, .oprofile_cpu_type = "ppc/e500", - .oprofile_type = PPC_OPROFILE_BOOKE, + .oprofile_type = PPC_OPROFILE_FSL_EMB, .machine_check = machine_check_e500, .platform = "ppc8540", }, @@ -1453,7 +1453,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .num_pmcs = 4, .oprofile_cpu_type = "ppc/e500", - .oprofile_type = PPC_OPROFILE_BOOKE, + .oprofile_type = PPC_OPROFILE_FSL_EMB, .machine_check = machine_check_e500, .platform = "ppc8548", }, diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index ea04e0ab3f2f..0516e2d3e02e 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -26,7 +26,7 @@ static void dummy_perf(struct pt_regs *regs) { -#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200) +#if defined(CONFIG_FSL_EMB_PERFMON) mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE); #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) if (cur_cpu_spec->pmc_type == PPC_PMC_IBM) diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile index c5f64c3bd668..2ef6b0dddd8c 100644 --- a/arch/powerpc/oprofile/Makefile +++ b/arch/powerpc/oprofile/Makefile @@ -15,5 +15,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \ cell/spu_profiler.o cell/vma_map.o \ cell/spu_task_sync.o oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o -oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o +oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o oprofile-$(CONFIG_6xx) += op_model_7450.o diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index a28cce1d6c24..4908dc98f9ca 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) model = &op_model_7450; break; #endif -#ifdef CONFIG_FSL_BOOKE - case PPC_OPROFILE_BOOKE: - model = &op_model_fsl_booke; +#if defined(CONFIG_FSL_EMB_PERFMON) + case PPC_OPROFILE_FSL_EMB: + model = &op_model_fsl_emb; break; #endif default: diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c deleted file mode 100644 index 183a28bb1812..000000000000 --- a/arch/powerpc/oprofile/op_model_fsl_booke.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * arch/powerpc/oprofile/op_model_fsl_booke.c - * - * Freescale Book-E oprofile support, based on ppc64 oprofile support - * Copyright (C) 2004 Anton Blanchard , IBM - * - * Copyright (c) 2004 Freescale Semiconductor, Inc - * - * Author: Andy Fleming - * Maintainer: Kumar Gala - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned long reset_value[OP_MAX_COUNTER]; - -static int num_counters; -static int oprofile_running; - -static inline u32 get_pmlca(int ctr) -{ - u32 pmlca; - - switch (ctr) { - case 0: - pmlca = mfpmr(PMRN_PMLCA0); - break; - case 1: - pmlca = mfpmr(PMRN_PMLCA1); - break; - case 2: - pmlca = mfpmr(PMRN_PMLCA2); - break; - case 3: - pmlca = mfpmr(PMRN_PMLCA3); - break; - default: - panic("Bad ctr number\n"); - } - - return pmlca; -} - -static inline void set_pmlca(int ctr, u32 pmlca) -{ - switch (ctr) { - case 0: - mtpmr(PMRN_PMLCA0, pmlca); - break; - case 1: - mtpmr(PMRN_PMLCA1, pmlca); - break; - case 2: - mtpmr(PMRN_PMLCA2, pmlca); - break; - case 3: - mtpmr(PMRN_PMLCA3, pmlca); - break; - default: - panic("Bad ctr number\n"); - } -} - -static inline unsigned int ctr_read(unsigned int i) -{ - switch(i) { - case 0: - return mfpmr(PMRN_PMC0); - case 1: - return mfpmr(PMRN_PMC1); - case 2: - return mfpmr(PMRN_PMC2); - case 3: - return mfpmr(PMRN_PMC3); - default: - return 0; - } -} - -static inline void ctr_write(unsigned int i, unsigned int val) -{ - switch(i) { - case 0: - mtpmr(PMRN_PMC0, val); - break; - case 1: - mtpmr(PMRN_PMC1, val); - break; - case 2: - mtpmr(PMRN_PMC2, val); - break; - case 3: - mtpmr(PMRN_PMC3, val); - break; - default: - break; - } -} - - -static void init_pmc_stop(int ctr) -{ - u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU | - PMLCA_FCM1 | PMLCA_FCM0); - u32 pmlcb = 0; - - switch (ctr) { - case 0: - mtpmr(PMRN_PMLCA0, pmlca); - mtpmr(PMRN_PMLCB0, pmlcb); - break; - case 1: - mtpmr(PMRN_PMLCA1, pmlca); - mtpmr(PMRN_PMLCB1, pmlcb); - break; - case 2: - mtpmr(PMRN_PMLCA2, pmlca); - mtpmr(PMRN_PMLCB2, pmlcb); - break; - case 3: - mtpmr(PMRN_PMLCA3, pmlca); - mtpmr(PMRN_PMLCB3, pmlcb); - break; - default: - panic("Bad ctr number!\n"); - } -} - -static void set_pmc_event(int ctr, int event) -{ - u32 pmlca; - - pmlca = get_pmlca(ctr); - - pmlca = (pmlca & ~PMLCA_EVENT_MASK) | - ((event << PMLCA_EVENT_SHIFT) & - PMLCA_EVENT_MASK); - - set_pmlca(ctr, pmlca); -} - -static void set_pmc_user_kernel(int ctr, int user, int kernel) -{ - u32 pmlca; - - pmlca = get_pmlca(ctr); - - if(user) - pmlca &= ~PMLCA_FCU; - else - pmlca |= PMLCA_FCU; - - if(kernel) - pmlca &= ~PMLCA_FCS; - else - pmlca |= PMLCA_FCS; - - set_pmlca(ctr, pmlca); -} - -static void set_pmc_marked(int ctr, int mark0, int mark1) -{ - u32 pmlca = get_pmlca(ctr); - - if(mark0) - pmlca &= ~PMLCA_FCM0; - else - pmlca |= PMLCA_FCM0; - - if(mark1) - pmlca &= ~PMLCA_FCM1; - else - pmlca |= PMLCA_FCM1; - - set_pmlca(ctr, pmlca); -} - -static void pmc_start_ctr(int ctr, int enable) -{ - u32 pmlca = get_pmlca(ctr); - - pmlca &= ~PMLCA_FC; - - if (enable) - pmlca |= PMLCA_CE; - else - pmlca &= ~PMLCA_CE; - - set_pmlca(ctr, pmlca); -} - -static void pmc_start_ctrs(int enable) -{ - u32 pmgc0 = mfpmr(PMRN_PMGC0); - - pmgc0 &= ~PMGC0_FAC; - pmgc0 |= PMGC0_FCECE; - - if (enable) - pmgc0 |= PMGC0_PMIE; - else - pmgc0 &= ~PMGC0_PMIE; - - mtpmr(PMRN_PMGC0, pmgc0); -} - -static void pmc_stop_ctrs(void) -{ - u32 pmgc0 = mfpmr(PMRN_PMGC0); - - pmgc0 |= PMGC0_FAC; - - pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE); - - mtpmr(PMRN_PMGC0, pmgc0); -} - -static void dump_pmcs(void) -{ - printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0)); - printk("pmc\t\tpmlca\t\tpmlcb\n"); - printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0), - mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0)); - printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1), - mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1)); - printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2), - mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2)); - printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3), - mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); -} - -static int fsl_booke_cpu_setup(struct op_counter_config *ctr) -{ - int i; - - /* freeze all counters */ - pmc_stop_ctrs(); - - for (i = 0;i < num_counters;i++) { - init_pmc_stop(i); - - set_pmc_event(i, ctr[i].event); - - set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); - } - - return 0; -} - -static int fsl_booke_reg_setup(struct op_counter_config *ctr, - struct op_system_config *sys, - int num_ctrs) -{ - int i; - - num_counters = num_ctrs; - - /* Our counters count up, and "count" refers to - * how much before the next interrupt, and we interrupt - * on overflow. So we calculate the starting value - * which will give us "count" until overflow. - * Then we set the events on the enabled counters */ - for (i = 0; i < num_counters; ++i) - reset_value[i] = 0x80000000UL - ctr[i].count; - - return 0; -} - -static int fsl_booke_start(struct op_counter_config *ctr) -{ - int i; - - mtmsr(mfmsr() | MSR_PMM); - - for (i = 0; i < num_counters; ++i) { - if (ctr[i].enabled) { - ctr_write(i, reset_value[i]); - /* Set each enabled counter to only - * count when the Mark bit is *not* set */ - set_pmc_marked(i, 1, 0); - pmc_start_ctr(i, 1); - } else { - ctr_write(i, 0); - - /* Set the ctr to be stopped */ - pmc_start_ctr(i, 0); - } - } - - /* Clear the freeze bit, and enable the interrupt. - * The counters won't actually start until the rfi clears - * the PMM bit */ - pmc_start_ctrs(1); - - oprofile_running = 1; - - pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), - mfpmr(PMRN_PMGC0)); - - return 0; -} - -static void fsl_booke_stop(void) -{ - /* freeze counters */ - pmc_stop_ctrs(); - - oprofile_running = 0; - - pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(), - mfpmr(PMRN_PMGC0)); - - mb(); -} - - -static void fsl_booke_handle_interrupt(struct pt_regs *regs, - struct op_counter_config *ctr) -{ - unsigned long pc; - int is_kernel; - int val; - int i; - - /* set the PMM bit (see comment below) */ - mtmsr(mfmsr() | MSR_PMM); - - pc = regs->nip; - is_kernel = is_kernel_addr(pc); - - for (i = 0; i < num_counters; ++i) { - val = ctr_read(i); - if (val < 0) { - if (oprofile_running && ctr[i].enabled) { - oprofile_add_ext_sample(pc, regs, i, is_kernel); - ctr_write(i, reset_value[i]); - } else { - ctr_write(i, 0); - } - } - } - - /* The freeze bit was set by the interrupt. */ - /* Clear the freeze bit, and reenable the interrupt. - * The counters won't actually start until the rfi clears - * the PMM bit */ - pmc_start_ctrs(1); -} - -struct op_powerpc_model op_model_fsl_booke = { - .reg_setup = fsl_booke_reg_setup, - .cpu_setup = fsl_booke_cpu_setup, - .start = fsl_booke_start, - .stop = fsl_booke_stop, - .handle_interrupt = fsl_booke_handle_interrupt, -}; diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c new file mode 100644 index 000000000000..91596f6ba1f4 --- /dev/null +++ b/arch/powerpc/oprofile/op_model_fsl_emb.c @@ -0,0 +1,369 @@ +/* + * Freescale Embedded oprofile support, based on ppc64 oprofile support + * Copyright (C) 2004 Anton Blanchard , IBM + * + * Copyright (c) 2004 Freescale Semiconductor, Inc + * + * Author: Andy Fleming + * Maintainer: Kumar Gala + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long reset_value[OP_MAX_COUNTER]; + +static int num_counters; +static int oprofile_running; + +static inline u32 get_pmlca(int ctr) +{ + u32 pmlca; + + switch (ctr) { + case 0: + pmlca = mfpmr(PMRN_PMLCA0); + break; + case 1: + pmlca = mfpmr(PMRN_PMLCA1); + break; + case 2: + pmlca = mfpmr(PMRN_PMLCA2); + break; + case 3: + pmlca = mfpmr(PMRN_PMLCA3); + break; + default: + panic("Bad ctr number\n"); + } + + return pmlca; +} + +static inline void set_pmlca(int ctr, u32 pmlca) +{ + switch (ctr) { + case 0: + mtpmr(PMRN_PMLCA0, pmlca); + break; + case 1: + mtpmr(PMRN_PMLCA1, pmlca); + break; + case 2: + mtpmr(PMRN_PMLCA2, pmlca); + break; + case 3: + mtpmr(PMRN_PMLCA3, pmlca); + break; + default: + panic("Bad ctr number\n"); + } +} + +static inline unsigned int ctr_read(unsigned int i) +{ + switch(i) { + case 0: + return mfpmr(PMRN_PMC0); + case 1: + return mfpmr(PMRN_PMC1); + case 2: + return mfpmr(PMRN_PMC2); + case 3: + return mfpmr(PMRN_PMC3); + default: + return 0; + } +} + +static inline void ctr_write(unsigned int i, unsigned int val) +{ + switch(i) { + case 0: + mtpmr(PMRN_PMC0, val); + break; + case 1: + mtpmr(PMRN_PMC1, val); + break; + case 2: + mtpmr(PMRN_PMC2, val); + break; + case 3: + mtpmr(PMRN_PMC3, val); + break; + default: + break; + } +} + + +static void init_pmc_stop(int ctr) +{ + u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU | + PMLCA_FCM1 | PMLCA_FCM0); + u32 pmlcb = 0; + + switch (ctr) { + case 0: + mtpmr(PMRN_PMLCA0, pmlca); + mtpmr(PMRN_PMLCB0, pmlcb); + break; + case 1: + mtpmr(PMRN_PMLCA1, pmlca); + mtpmr(PMRN_PMLCB1, pmlcb); + break; + case 2: + mtpmr(PMRN_PMLCA2, pmlca); + mtpmr(PMRN_PMLCB2, pmlcb); + break; + case 3: + mtpmr(PMRN_PMLCA3, pmlca); + mtpmr(PMRN_PMLCB3, pmlcb); + break; + default: + panic("Bad ctr number!\n"); + } +} + +static void set_pmc_event(int ctr, int event) +{ + u32 pmlca; + + pmlca = get_pmlca(ctr); + + pmlca = (pmlca & ~PMLCA_EVENT_MASK) | + ((event << PMLCA_EVENT_SHIFT) & + PMLCA_EVENT_MASK); + + set_pmlca(ctr, pmlca); +} + +static void set_pmc_user_kernel(int ctr, int user, int kernel) +{ + u32 pmlca; + + pmlca = get_pmlca(ctr); + + if(user) + pmlca &= ~PMLCA_FCU; + else + pmlca |= PMLCA_FCU; + + if(kernel) + pmlca &= ~PMLCA_FCS; + else + pmlca |= PMLCA_FCS; + + set_pmlca(ctr, pmlca); +} + +static void set_pmc_marked(int ctr, int mark0, int mark1) +{ + u32 pmlca = get_pmlca(ctr); + + if(mark0) + pmlca &= ~PMLCA_FCM0; + else + pmlca |= PMLCA_FCM0; + + if(mark1) + pmlca &= ~PMLCA_FCM1; + else + pmlca |= PMLCA_FCM1; + + set_pmlca(ctr, pmlca); +} + +static void pmc_start_ctr(int ctr, int enable) +{ + u32 pmlca = get_pmlca(ctr); + + pmlca &= ~PMLCA_FC; + + if (enable) + pmlca |= PMLCA_CE; + else + pmlca &= ~PMLCA_CE; + + set_pmlca(ctr, pmlca); +} + +static void pmc_start_ctrs(int enable) +{ + u32 pmgc0 = mfpmr(PMRN_PMGC0); + + pmgc0 &= ~PMGC0_FAC; + pmgc0 |= PMGC0_FCECE; + + if (enable) + pmgc0 |= PMGC0_PMIE; + else + pmgc0 &= ~PMGC0_PMIE; + + mtpmr(PMRN_PMGC0, pmgc0); +} + +static void pmc_stop_ctrs(void) +{ + u32 pmgc0 = mfpmr(PMRN_PMGC0); + + pmgc0 |= PMGC0_FAC; + + pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE); + + mtpmr(PMRN_PMGC0, pmgc0); +} + +static void dump_pmcs(void) +{ + printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0)); + printk("pmc\t\tpmlca\t\tpmlcb\n"); + printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0), + mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0)); + printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1), + mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1)); + printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2), + mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2)); + printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3), + mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); +} + +static int fsl_emb_cpu_setup(struct op_counter_config *ctr) +{ + int i; + + /* freeze all counters */ + pmc_stop_ctrs(); + + for (i = 0;i < num_counters;i++) { + init_pmc_stop(i); + + set_pmc_event(i, ctr[i].event); + + set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); + } + + return 0; +} + +static int fsl_emb_reg_setup(struct op_counter_config *ctr, + struct op_system_config *sys, + int num_ctrs) +{ + int i; + + num_counters = num_ctrs; + + /* Our counters count up, and "count" refers to + * how much before the next interrupt, and we interrupt + * on overflow. So we calculate the starting value + * which will give us "count" until overflow. + * Then we set the events on the enabled counters */ + for (i = 0; i < num_counters; ++i) + reset_value[i] = 0x80000000UL - ctr[i].count; + + return 0; +} + +static int fsl_emb_start(struct op_counter_config *ctr) +{ + int i; + + mtmsr(mfmsr() | MSR_PMM); + + for (i = 0; i < num_counters; ++i) { + if (ctr[i].enabled) { + ctr_write(i, reset_value[i]); + /* Set each enabled counter to only + * count when the Mark bit is *not* set */ + set_pmc_marked(i, 1, 0); + pmc_start_ctr(i, 1); + } else { + ctr_write(i, 0); + + /* Set the ctr to be stopped */ + pmc_start_ctr(i, 0); + } + } + + /* Clear the freeze bit, and enable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + pmc_start_ctrs(1); + + oprofile_running = 1; + + pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), + mfpmr(PMRN_PMGC0)); + + return 0; +} + +static void fsl_emb_stop(void) +{ + /* freeze counters */ + pmc_stop_ctrs(); + + oprofile_running = 0; + + pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(), + mfpmr(PMRN_PMGC0)); + + mb(); +} + + +static void fsl_emb_handle_interrupt(struct pt_regs *regs, + struct op_counter_config *ctr) +{ + unsigned long pc; + int is_kernel; + int val; + int i; + + /* set the PMM bit (see comment below) */ + mtmsr(mfmsr() | MSR_PMM); + + pc = regs->nip; + is_kernel = is_kernel_addr(pc); + + for (i = 0; i < num_counters; ++i) { + val = ctr_read(i); + if (val < 0) { + if (oprofile_running && ctr[i].enabled) { + oprofile_add_ext_sample(pc, regs, i, is_kernel); + ctr_write(i, reset_value[i]); + } else { + ctr_write(i, 0); + } + } + } + + /* The freeze bit was set by the interrupt. */ + /* Clear the freeze bit, and reenable the interrupt. + * The counters won't actually start until the rfi clears + * the PMM bit */ + pmc_start_ctrs(1); +} + +struct op_powerpc_model op_model_fsl_emb = { + .reg_setup = fsl_emb_reg_setup, + .cpu_setup = fsl_emb_cpu_setup, + .start = fsl_emb_start, + .stop = fsl_emb_stop, + .handle_interrupt = fsl_emb_handle_interrupt, +}; diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 7fc41104d53e..eea2e7049fed 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -94,6 +94,7 @@ config 8xx bool config E500 + select FSL_EMB_PERFMON bool config PPC_FPU @@ -115,6 +116,9 @@ config FSL_BOOKE depends on E200 || E500 default y +config FSL_EMB_PERFMON + bool + config PTE_64BIT bool depends on 44x || E500 -- cgit v1.2.2 From 1347a2c1eb61fce8b5085801761c7b63f9e7ba8b Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Mon, 4 Feb 2008 18:28:07 -0600 Subject: [POWERPC} Add oprofile support for e300 The e300 c3 and c4 variants support hardware performance monitor counters which are identical to those found in the e500. Signed-off-by: Andy Fleming Signed-off-by: Kumar Gala --- arch/powerpc/kernel/cputable.c | 6 ++++++ arch/powerpc/platforms/Kconfig | 1 + 2 files changed, 7 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 98a1c9e6b9fa..2a8f5cc5184f 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -959,6 +959,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .icache_bsize = 32, .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, + .num_pmcs = 4, + .oprofile_cpu_type = "ppc/e300", + .oprofile_type = PPC_OPROFILE_FSL_EMB, .platform = "ppc603", }, { /* e300c4 (e300c1, plus one IU) */ @@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = { .dcache_bsize = 32, .cpu_setup = __setup_cpu_603, .machine_check = machine_check_generic, + .num_pmcs = 4, + .oprofile_cpu_type = "ppc/e300", + .oprofile_type = PPC_OPROFILE_FSL_EMB, .platform = "ppc603", }, { /* default match, we assume split I/D cache & TB (non-601)... */ diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index fdce10c4f074..045b8c80eeaf 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -24,6 +24,7 @@ config PPC_83xx select MPC83xx select IPIC select WANT_DEVICE_TREE + select FSL_EMB_PERFMON config PPC_86xx bool "Freescale 86xx" -- cgit v1.2.2 From aafa1955501955bf4e53b72fee0be9f35b711b9d Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 1 Feb 2008 18:09:54 -0600 Subject: [POWERPC] 83xx: mpc832x_rdb: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arch/powerpc/platforms/83xx/mpc832x_rdb.c: In function ‘mpc832x_rdb_setup_arch’: arch/powerpc/platforms/83xx/mpc832x_rdb.c:104: warning: ‘np’ is used uninitialized in this function Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/platforms/83xx/mpc832x_rdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 9f0fd88b2b1f..e7f706b624fe 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c @@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void) #ifdef CONFIG_QUICC_ENGINE qe_reset(); - if ((np = of_find_node_by_name(np, "par_io")) != NULL) { + if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { par_io_init(np); of_node_put(np); -- cgit v1.2.2 From dc4e4207ed7dc256fed1626fbf087cb199cd1945 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 1 Feb 2008 18:09:58 -0600 Subject: [POWERPC] FSL: fix mpc83xx_spi device registration calling platform_device_register after platform_device_alloc causes this: kobject (c3841a70): tried to init an initialized object, something is seriously wrong. Call Trace: [c381fe20] [c0007bb8] show_stack+0x3c/0x194 (unreliable) [c381fe50] [c01322a8] kobject_init+0xb8/0xbc [c381fe60] [c01591cc] device_initialize+0x30/0x9c [c381fe80] [c015ee34] platform_device_register+0x1c/0x34 [c381fea0] [c02f1fe0] of_fsl_spi_probe+0x21c/0x22c [c381ff30] [c02f2044] fsl_spi_init+0x54/0x160 [c381ff60] [c02f3924] __machine_initcall_mpc832x_rdb_mpc832x_spi_init+0x120/0x138 [c381ff70] [c02e61b4] kernel_init+0x98/0x284 [c381fff0] [c000f740] kernel_thread+0x44/0x60 fixed by calling platform_device_add (second half of platform_device_register) instead. Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index e48b20e934ca..2c5388ce902a 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -1342,7 +1342,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk, if (ret) goto unreg; - ret = platform_device_register(pdev); + ret = platform_device_add(pdev); if (ret) goto unreg; -- cgit v1.2.2 From e1664ee9f3dabda088debec12ef5322d8bd8ba01 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 1 Feb 2008 18:10:03 -0600 Subject: [POWERPC] 83xx: Update mpc83xx_defconfig Enable math emulation and ucc_geth and some PHYs mpc83xx boards use. Signed-off-by: Kim Phillips Signed-off-by: Kumar Gala --- arch/powerpc/configs/mpc83xx_defconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig index 31bdbf3f7566..a9807f083bc4 100644 --- a/arch/powerpc/configs/mpc83xx_defconfig +++ b/arch/powerpc/configs/mpc83xx_defconfig @@ -186,7 +186,7 @@ CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_MATH_EMULATION is not set +CONFIG_MATH_EMULATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_POPULATES_NODE_MAP=y @@ -416,14 +416,14 @@ CONFIG_PHYLIB=y # MII PHY device drivers # CONFIG_MARVELL_PHY=y -# CONFIG_DAVICOM_PHY is not set +CONFIG_DAVICOM_PHY=y # CONFIG_QSEMI_PHY is not set # CONFIG_LXT_PHY is not set # CONFIG_CICADA_PHY is not set -# CONFIG_VITESSE_PHY is not set +CONFIG_VITESSE_PHY=y # CONFIG_SMSC_PHY is not set # CONFIG_BROADCOM_PHY is not set -# CONFIG_ICPLUS_PHY is not set +CONFIG_ICPLUS_PHY=y # CONFIG_FIXED_PHY is not set # CONFIG_MDIO_BITBANG is not set CONFIG_NET_ETHERNET=y @@ -436,7 +436,7 @@ CONFIG_MII=y CONFIG_NETDEV_1000=y CONFIG_GIANFAR=y # CONFIG_GFAR_NAPI is not set -# CONFIG_UCC_GETH is not set +CONFIG_UCC_GETH=y CONFIG_NETDEV_10000=y # -- cgit v1.2.2 From d8985fd2b8ef8994399ea33f7e5b24395f5a7cab Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Mon, 4 Feb 2008 16:46:17 +0300 Subject: [POWERPC] qe_lib: fix few fluffy negligences One is intoduced by me (of_node_put() absence) and another was present already (not checking for NULL). Found by Stephen Rothwell. Signed-off-by: Anton Vorontsov Acked-by: Stephen Rothwell Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/qe_lib/qe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 5ef844da9355..6efbd5e5bb1b 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void) { struct device_node *qe; unsigned int size; - const void *prop; + const u32 *prop; if (qebase != -1) return qebase; @@ -79,7 +79,8 @@ phys_addr_t get_qe_base(void) } prop = of_get_property(qe, "reg", &size); - qebase = of_translate_address(qe, prop); + if (prop && size >= sizeof(*prop)) + qebase = of_translate_address(qe, prop); of_node_put(qe); return qebase; @@ -172,10 +173,9 @@ unsigned int get_brg_clk(void) } prop = of_get_property(qe, "brg-frequency", &size); - if (!prop || size != sizeof(*prop)) - return brg_clk; + if (prop && size == sizeof(*prop)) + brg_clk = *prop; - brg_clk = *prop; of_node_put(qe); return brg_clk; -- cgit v1.2.2 From 7e25867fe8d705bcf707ef52004b669eb795d06d Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 5 Feb 2008 23:58:30 -0600 Subject: [POWERPC] 85xx: Add second cpu to 8572 dts The 8572 is a dual core processor, not reason not to describe both cores in the device tree. Signed-off-by: Kumar Gala --- arch/powerpc/boot/dts/mpc8572ds.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts index 813c259abbe5..db37214aee37 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dts +++ b/arch/powerpc/boot/dts/mpc8572ds.dts @@ -42,6 +42,18 @@ bus-frequency = <0>; clock-frequency = <0>; }; + + PowerPC,8572@1 { + device_type = "cpu"; + reg = <1>; + d-cache-line-size = <20>; // 32 bytes + i-cache-line-size = <20>; // 32 bytes + d-cache-size = <8000>; // L1, 32K + i-cache-size = <8000>; // L1, 32K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; }; memory { -- cgit v1.2.2 From 842decbd674106d63a67e07a2f8cec5af70fdb40 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Feb 2008 23:34:58 -0800 Subject: [POWERPC] arch/powerpc/platforms/pseries: Add missing of_node_put Of_get_parent and of_find_compatible_node do an of_node_get, and thus a corresponding of_code_put is needed in the error case. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @@ type T,T1,T2; identifier E; statement S; expression x1,x2,x3; int ret; @@ T E; ... * E = \(of_get_parent\|of_find_compatible_node\)(...); if (E == NULL) S ... when != of_node_put(...,(T1)E,...) when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...} when != x1 = (T1)E when != E = x3; when any if (...) { ... when != of_node_put(...,(T2)E,...) when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...} when != x2 = (T2)E ( * return; | * return ret; ) } // Signed-off-by: Julia Lawall Cc: Stephen Rothwell Cc: Benjamin Herrenschmidt Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/reconfig.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index c02f8742c54d..2800fced8c7c 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -167,6 +167,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) if ((child = of_get_next_child(np, NULL))) { of_node_put(child); + of_node_put(parent); return -EBUSY; } -- cgit v1.2.2 From b1725c9319aae42d7bd1159fc99e033d5a3076f8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Feb 2008 23:34:59 -0800 Subject: [POWERPC] arch/powerpc/sysdev: Add missing of_node_put The functions of_find_compatible_node and of_find_node_by_type both call of_node_get on their result. So any error handling code thereafter should call of_node_put(np). This is taken care of in the case where there is a goto out, but not when there is a direct return. The function irq_alloc_host puts np into the returned structure, which is stored in the global variable mpc8xx_pic_host, so the reference count should be set for the lifetime of that variable. The current solution ups the reference count again in the argument to irq_alloc_host so that it can be decremented on the way out. This seems a bit unnecessary, and also doesn't work in the case where irq_alloc_host fails, because then the reference count only goes does by one, whereas it should go down by two. A better solution is to not increment the reference count in the argument to irq_alloc_host and only decrement it on the way out in an error case. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @@ type T,T1,T2; identifier E; statement S; expression x1,x2,x3; int ret; @@ T E; ... * E = \(of_get_parent\|of_find_compatible_node\)(...); if (E == NULL) S ... when != of_node_put(...,(T1)E,...) when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...} when != x1 = (T1)E when != E = x3; when any if (...) { ... when != of_node_put(...,(T2)E,...) when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...} when != x2 = (T2)E ( * return; | * return ret; ) } // Signed-off-by: Julia Lawall Cc: Stephen Rothwell Cc: Benjamin Herrenschmidt Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/sysdev/mpc8xx_pic.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 0e74a4bd9827..5d2d5522ef41 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -174,15 +174,19 @@ int mpc8xx_pic_init(void) goto out; siu_reg = ioremap(res.start, res.end - res.start + 1); - if (siu_reg == NULL) - return -EINVAL; + if (siu_reg == NULL) { + ret = -EINVAL; + goto out; + } - mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR, + mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 64, &mpc8xx_pic_host_ops, 64); if (mpc8xx_pic_host == NULL) { printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n"); ret = -ENOMEM; + goto out; } + return 0; out: of_node_put(np); -- cgit v1.2.2 From 75e89b02e338d0db27f8e5d66642c7e2ae49c326 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Feb 2008 23:35:00 -0800 Subject: [POWERPC] arch/powerpc/platforms/82xx: Add missing of_node_put Of_get_parent and of_find_compatible_node do a of_node_get, and thus a corresponding of_code_put is needed in both the error case and the normal return case. The problem was found using the following semantic match. (http://www.emn.fr/x-info/coccinelle/) // @@ type T,T1,T2; identifier E; statement S; expression x1,x2,x3; int ret; @@ T E; ... * E = \(of_get_parent\|of_find_compatible_node\)(...); if (E == NULL) S ... when != of_node_put(...,(T1)E,...) when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...} when != x1 = (T1)E when != E = x3; when any if (...) { ... when != of_node_put(...,(T2)E,...) when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...} when != x2 = (T2)E ( * return; | * return ret; ) } // Signed-off-by: Julia Lawall Cc: Stephen Rothwell Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/82xx/mpc8272_ads.c | 3 +-- arch/powerpc/platforms/82xx/pq2fads.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index 3fce6b375dbc..7d3018751988 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c @@ -134,13 +134,12 @@ static void __init mpc8272_ads_setup_arch(void) } bcsr = of_iomap(np, 0); + of_node_put(np); if (!bcsr) { printk(KERN_ERR "Cannot map BCSR registers\n"); return; } - of_node_put(np); - clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); setbits32(&bcsr[1], BCSR1_FETH_RST); diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c index 68196e349994..e1dceeec4994 100644 --- a/arch/powerpc/platforms/82xx/pq2fads.c +++ b/arch/powerpc/platforms/82xx/pq2fads.c @@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void) } bcsr = of_iomap(np, 0); + of_node_put(np); if (!bcsr) { printk(KERN_ERR "Cannot map BCSR registers\n"); return; } - of_node_put(np); - /* Enable the serial and ethernet ports */ clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN); -- cgit v1.2.2 From 0e349b0e2d90eb1bb76d16c48d0127feebfeeb89 Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Wed, 9 Jan 2008 06:35:05 +1100 Subject: [POWERPC] Xilinx: Update compatible to use values generated by BSP generator. Mainly, this involves two changes: 1) xilinx->xlnx (recognized standard is to use the stock ticker) 2) In order to have the device tree focus on describing what the hardware is as exactly as possible, the compatible strings contain the full IP name and IP version. Signed-off-by: Stephen Neuendorffer Acked-by: Peter Korsgaard Signed-off-by: Grant Likely --- arch/powerpc/platforms/40x/virtex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c index 88b66444dfb2..0422590040db 100644 --- a/arch/powerpc/platforms/40x/virtex.c +++ b/arch/powerpc/platforms/40x/virtex.c @@ -37,7 +37,7 @@ static int __init virtex_probe(void) { unsigned long root = of_get_flat_dt_root(); - if (!of_flat_dt_is_compatible(root, "xilinx,virtex")) + if (!of_flat_dt_is_compatible(root, "xlnx,virtex")) return 0; return 1; -- cgit v1.2.2 From e177edcd1505d5ac5f2edcd1f2df76946f4eae5d Mon Sep 17 00:00:00 2001 From: John Rigby Date: Tue, 29 Jan 2008 04:28:53 +1100 Subject: [POWERPC] mpc512x: Basic platform support 512x is very similar to 83xx and most of this is patterned after code from 83xx. New platform: changed: arch/powerpc/Kconfig arch/powerpc/platforms/Kconfig arch/powerpc/platforms/Kconfig.cputype arch/powerpc/platforms/Makefile new: arch/powerpc/platforms/512x/* include/asm-powerpc/mpc512x.h Signed-off-by: John Rigby Signed-off-by: Grant Likely --- arch/powerpc/Kconfig | 2 +- arch/powerpc/platforms/512x/Kconfig | 20 ++++++ arch/powerpc/platforms/512x/Makefile | 4 ++ arch/powerpc/platforms/512x/mpc5121_ads.c | 104 ++++++++++++++++++++++++++++++ arch/powerpc/platforms/Kconfig | 1 + arch/powerpc/platforms/Kconfig.cputype | 6 +- arch/powerpc/platforms/Makefile | 1 + 7 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 arch/powerpc/platforms/512x/Kconfig create mode 100644 arch/powerpc/platforms/512x/Makefile create mode 100644 arch/powerpc/platforms/512x/mpc5121_ads.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 2bf2f3f53029..88ea64bd991a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -489,7 +489,7 @@ config PCI bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \ || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \ || PPC_PS3 || 44x - default y if !40x && !CPM2 && !8xx && !PPC_83xx \ + default y if !40x && !CPM2 && !8xx && !PPC_MPC512x && !PPC_83xx \ && !PPC_85xx && !PPC_86xx default PCI_PERMEDIA if !4xx && !CPM2 && !8xx default PCI_QSPAN if !4xx && !CPM2 && 8xx diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig new file mode 100644 index 000000000000..c6fa49e23dc0 --- /dev/null +++ b/arch/powerpc/platforms/512x/Kconfig @@ -0,0 +1,20 @@ +config PPC_MPC512x + bool + select FSL_SOC + select IPIC + default n + +config PPC_MPC5121 + bool + select PPC_MPC512x + default n + +config MPC5121_ADS + bool "Freescale MPC5121E ADS" + depends on PPC_MULTIPLATFORM && PPC32 + select DEFAULT_UIMAGE + select WANT_DEVICE_TREE + select PPC_MPC5121 + help + This option enables support for the MPC5121E ADS board. + default n diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile new file mode 100644 index 000000000000..232c89f2039a --- /dev/null +++ b/arch/powerpc/platforms/512x/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the Freescale PowerPC 512x linux kernel. +# +obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c new file mode 100644 index 000000000000..50bd3a319022 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: John Rigby, , Thur Mar 29 2007 + * + * Description: + * MPC5121 ADS board setup + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/** + * mpc512x_find_ips_freq - Find the IPS bus frequency for a device + * @node: device node + * + * Returns IPS bus frequency, or 0 if the bus frequency cannot be found. + */ +unsigned long +mpc512x_find_ips_freq(struct device_node *node) +{ + struct device_node *np; + const unsigned int *p_ips_freq = NULL; + + of_node_get(node); + while (node) { + p_ips_freq = of_get_property(node, "bus-frequency", NULL); + if (p_ips_freq) + break; + + np = of_get_parent(node); + of_node_put(node); + node = np; + } + if (node) + of_node_put(node); + + return p_ips_freq ? *p_ips_freq : 0; +} +EXPORT_SYMBOL(mpc512x_find_ips_freq); + +static struct of_device_id __initdata of_bus_ids[] = { + { .name = "soc", }, + { .name = "localbus", }, + {}, +}; + +static void __init mpc5121_ads_declare_of_platform_devices(void) +{ + /* Find every child of the SOC node and add it to of_platform */ + if (of_platform_bus_probe(NULL, of_bus_ids, NULL)) + printk(KERN_ERR __FILE__ ": " + "Error while probing of_platform bus\n"); +} + +static void __init mpc5121_ads_init_IRQ(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); + if (!np) + return; + + ipic_init(np, 0); + of_node_put(np); + + /* + * Initialize the default interrupt mapping priorities, + * in case the boot rom changed something on us. + */ + ipic_set_default_priority(); +} + +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc5121_ads_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + + return of_flat_dt_is_compatible(root, "fsl,mpc5121ads"); +} + +define_machine(mpc5121_ads) { + .name = "MPC5121 ADS", + .probe = mpc5121_ads_probe, + .init = mpc5121_ads_declare_of_platform_devices, + .init_IRQ = mpc5121_ads_init_IRQ, + .get_irq = ipic_get_irq, + .calibrate_decr = generic_calibrate_decr, +}; diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index fdce10c4f074..e2c952619805 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -41,6 +41,7 @@ config CLASSIC32 source "arch/powerpc/platforms/pseries/Kconfig" source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" +source "arch/powerpc/platforms/512x/Kconfig" source "arch/powerpc/platforms/52xx/Kconfig" source "arch/powerpc/platforms/powermac/Kconfig" source "arch/powerpc/platforms/prep/Kconfig" diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 7fc41104d53e..51030ab2a023 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -14,7 +14,7 @@ choice There are five families of 32 bit PowerPC chips supported. The most common ones are the desktop and server CPUs (601, 603, 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their - embedded 52xx/82xx/83xx/86xx counterparts. + embedded 512x/52xx/82xx/83xx/86xx counterparts. The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500 (85xx) each form a family of their own that is not compatible with the others. @@ -22,7 +22,7 @@ choice If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx. config 6xx - bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx" + bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx" select PPC_FPU config PPC_85xx @@ -221,7 +221,7 @@ config NR_CPUS config NOT_COHERENT_CACHE bool - depends on 4xx || 8xx || E200 + depends on 4xx || 8xx || E200 || PPC_MPC512x default y config CHECK_CACHE_COHERENCY diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 6d9079da5f5a..a984894466d9 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -11,6 +11,7 @@ endif obj-$(CONFIG_PPC_CHRP) += chrp/ obj-$(CONFIG_40x) += 40x/ obj-$(CONFIG_44x) += 44x/ +obj-$(CONFIG_PPC_MPC512x) += 512x/ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ obj-$(CONFIG_PPC_8xx) += 8xx/ obj-$(CONFIG_PPC_82xx) += 82xx/ -- cgit v1.2.2 From bd05f91f95b6ca692097f95244bdda25bd929216 Mon Sep 17 00:00:00 2001 From: John Rigby Date: Tue, 29 Jan 2008 04:28:54 +1100 Subject: [POWERPC] mpc512x: Device tree for MPC5121 ADS Minimal /dts-v1/ device tree for mpc5121 ads. port-number property in uart nodes will go away after the driver learns to use aliases Signed-off-by: John Rigby Signed-off-by: Grant Likely --- arch/powerpc/boot/dts/mpc5121ads.dts | 122 +++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 arch/powerpc/boot/dts/mpc5121ads.dts (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts new file mode 100644 index 000000000000..94ad7b2b241e --- /dev/null +++ b/arch/powerpc/boot/dts/mpc5121ads.dts @@ -0,0 +1,122 @@ +/* + * MPC5121E MDS Device Tree Source + * + * Copyright 2007 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/dts-v1/; + +/ { + model = "mpc5121ads"; + compatible = "fsl,mpc5121ads"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + PowerPC,5121@0 { + device_type = "cpu"; + reg = <0>; + d-cache-line-size = <0x20>; // 32 bytes + i-cache-line-size = <0x20>; // 32 bytes + d-cache-size = <0x8000>; // L1, 32K + i-cache-size = <0x8000>; // L1, 32K + timebase-frequency = <49500000>;// 49.5 MHz (csb/4) + bus-frequency = <198000000>; // 198 MHz csb bus + clock-frequency = <396000000>; // 396 MHz ppc core + }; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x10000000>; // 256MB at 0 + }; + + localbus@80000020 { + compatible = "fsl,mpc5121ads-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x80000020 0x40>; + + ranges = <0x0 0x0 0xfc000000 0x04000000 + 0x2 0x0 0x82000000 0x00008000>; + + flash@0,0 { + compatible = "cfi-flash"; + reg = <0 0x0 0x4000000>; + bank-width = <4>; + device-width = <1>; + }; + + board-control@2,0 { + compatible = "fsl,mpc5121ads-cpld"; + reg = <0x2 0x0 0x8000>; + }; + }; + + soc@80000000 { + compatible = "fsl,mpc5121-immr"; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + ranges = <0x0 0x80000000 0x400000>; + reg = <0x80000000 0x400000>; + bus-frequency = <66000000>; // 66 MHz ips bus + + + // IPIC + // interrupts cell = + // sense values match linux IORESOURCE_IRQ_* defines: + // sense == 8: Level, low assertion + // sense == 2: Edge, high-to-low change + // + ipic: interrupt-controller@c00 { + compatible = "fsl,mpc5121-ipic", "fsl,ipic"; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0xc00 0x100>; + }; + + // 512x PSCs are not 52xx PSCs compatible + // PSC3 serial port A aka ttyPSC0 + serial@11300 { + device_type = "serial"; + compatible = "fsl,mpc5121-psc-uart"; + // Logical port assignment needed until driver + // learns to use aliases + port-number = <0>; + cell-index = <3>; + reg = <0x11300 0x100>; + interrupts = <0x28 0x8>; // actually the fifo irq + interrupt-parent = < &ipic >; + }; + + // PSC4 serial port B aka ttyPSC1 + serial@11400 { + device_type = "serial"; + compatible = "fsl,mpc5121-psc-uart"; + // Logical port assignment needed until driver + // learns to use aliases + port-number = <1>; + cell-index = <4>; + reg = <0x11400 0x100>; + interrupts = <0x28 0x8>; // actually the fifo irq + interrupt-parent = < &ipic >; + }; + + pscsfifo@11f00 { + compatible = "fsl,mpc5121-psc-fifo"; + reg = <0x11f00 0x100>; + interrupts = <0x28 0x8>; + interrupt-parent = < &ipic >; + }; + }; +}; -- cgit v1.2.2 From 7dbb922cea70897dd0e76c6cf8a300b061ca2531 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 31 Jan 2008 14:34:47 +1100 Subject: [POWERPC] Fix compilation for CONFIG_DEBUGGER=n and CONFIG_KEXEC=y Looks like "[POWERPC] kdump shutdown hook support" broke builds when CONFIG_DEBUGGER=n and CONFIG_KEXEC=y, such as in g5_defconfig: arch/powerpc/kernel/crash.c: In function 'default_machine_crash_shutdown': arch/powerpc/kernel/crash.c:388: error: '__debugger_fault_handler' undeclared (first use in this function) arch/powerpc/kernel/crash.c:388: error: (Each undeclared identifier is reported only once arch/powerpc/kernel/crash.c:388: error: for each function it appears in.) Move the debugger hooks to under CONFIG_DEBUGGER || CONFIG_KEXEC, since that's when the crash code is enabled. (I should have caught this with my build-script pre-merge, my bad. :( ) Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 848a20475db8..4b5b7ff4f78b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -54,7 +54,7 @@ #endif #include -#ifdef CONFIG_DEBUGGER +#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs); int (*__debugger_ipi)(struct pt_regs *regs); int (*__debugger_bpt)(struct pt_regs *regs); -- cgit v1.2.2 From 1daa6d08d1257aa61f376c3cc4795660877fb9e3 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 1 Feb 2008 15:57:31 +1100 Subject: [POWERPC] Fake NUMA emulation for PowerPC Here's a dumb simple implementation of fake NUMA nodes for PowerPC. Fake NUMA nodes can be specified using the following command line option numa=fake= node range is of the format ,,... Each of the rangeX parameters is passed using memparse(). I find the patch useful for fake NUMA emulation on my simple PowerPC machine. I've tested it on a numa box with the following arguments numa=fake=512M numa=fake=512M,768M numa=fake=256M,512M mem=512M numa=fake=1G mem=768M numa=fake= without any numa= argument The other side-effect introduced by this patch is that; in the case where we don't have NUMA information, we now set a node online after adding each LMB. This node could very well be node 0, but in the case that we enable fake NUMA nodes, when we cross node boundaries, we need to set the new node online. Signed-off-by: Balbir Singh Signed-off-by: Paul Mackerras --- arch/powerpc/mm/numa.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index c12adc3ddffd..e9139d267ea4 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -24,6 +24,8 @@ static int numa_enabled = 1; +static char *cmdline __initdata; + static int numa_debug; #define dbg(args...) if (numa_debug) { printk(KERN_INFO args); } @@ -39,6 +41,53 @@ static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES]; static int min_common_depth; static int n_mem_addr_cells, n_mem_size_cells; +static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn, + unsigned int *nid) +{ + unsigned long long mem; + char *p = cmdline; + static unsigned int fake_nid; + static unsigned long long curr_boundary; + + /* + * Modify node id, iff we started creating NUMA nodes + * We want to continue from where we left of the last time + */ + if (fake_nid) + *nid = fake_nid; + /* + * In case there are no more arguments to parse, the + * node_id should be the same as the last fake node id + * (we've handled this above). + */ + if (!p) + return 0; + + mem = memparse(p, &p); + if (!mem) + return 0; + + if (mem < curr_boundary) + return 0; + + curr_boundary = mem; + + if ((end_pfn << PAGE_SHIFT) > mem) { + /* + * Skip commas and spaces + */ + while (*p == ',' || *p == ' ' || *p == '\t') + p++; + + cmdline = p; + fake_nid++; + *nid = fake_nid; + dbg("created new fake_node with id %d\n", fake_nid); + return 1; + } + return 0; +} + static void __cpuinit map_cpu_to_node(int cpu, int node) { numa_cpu_lookup_table[cpu] = node; @@ -344,6 +393,9 @@ static void __init parse_drconf_memory(struct device_node *memory) if (nid == 0xffff || nid >= MAX_NUMNODES) nid = default_nid; } + + fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT), + &nid); node_set_online(nid); size = numa_enforce_memory_limit(start, lmb_size); @@ -429,6 +481,8 @@ new_range: nid = of_node_to_nid_single(memory); if (nid < 0) nid = default_nid; + + fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid); node_set_online(nid); if (!(size = numa_enforce_memory_limit(start, size))) { @@ -461,7 +515,7 @@ static void __init setup_nonnuma(void) unsigned long top_of_ram = lmb_end_of_DRAM(); unsigned long total_ram = lmb_phys_mem_size(); unsigned long start_pfn, end_pfn; - unsigned int i; + unsigned int i, nid = 0; printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n", top_of_ram, total_ram); @@ -471,9 +525,11 @@ static void __init setup_nonnuma(void) for (i = 0; i < lmb.memory.cnt; ++i) { start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT; end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i); - add_active_range(0, start_pfn, end_pfn); + + fake_numa_create_new_node(end_pfn, &nid); + add_active_range(nid, start_pfn, end_pfn); + node_set_online(nid); } - node_set_online(0); } void __init dump_numa_cpu_topology(void) @@ -702,6 +758,10 @@ static int __init early_numa(char *p) if (strstr(p, "debug")) numa_debug = 1; + p = strstr(p, "fake="); + if (p) + cmdline = p + strlen("fake="); + return 0; } early_param("numa", early_numa); -- cgit v1.2.2 From 25431333813686654907ab987fb5de10c10a16db Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 7 Feb 2008 05:18:34 +1100 Subject: [POWERPC] bootwrapper: Build multiple cuImages Currently, the kernel uses CONFIG_DEVICE_TREE to wrap a kernel image with a fdt blob which means for any given configuration only one dts file can be selected and so support for only one board can be built This moves the selection of the default .dts file out of the kernel config and into the bootwrapper makefile. The makefile chooses which images to build based on the kernel config and the dts source file name is taken directly from the image name. For example "cuImage.ebony" will use "ebony.dts" as the device tree source file. In addition, this patch allows a specific image to be requested from the command line by adding "cuImage.%" and "treeImage.%" targets to the list of valid built targets in arch/powerpc/Makefile. This allows the default dts selection to be overridden. Another advantage to this change is it allows a single defconfig to be supplied for all boards using the same chip family and only differing in the device tree. Important note: This patch adds two new zImage targets; zImage.dtb.% and zImage.dtb.initrd.% for zImages with embedded dtb files. Currently there are 5 platforms which require this: ps3, ep405, mpc885ads, ep88xc, adder875-redboot and ep8248e. This patch *changes the zImage filenames* for those platforms. ie. 'zImage.ps3' is now 'zImage.dtb.ps3'. This new zImage.dtb targets were added so that the .dts file could be part of the dependancies list for building them. Signed-off-by: Grant Likely Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 19 ----- arch/powerpc/Makefile | 9 +-- arch/powerpc/boot/Makefile | 126 ++++++++++++++++++++------------- arch/powerpc/boot/cuboot-hpc2.c | 48 ------------- arch/powerpc/boot/cuboot-mpc7448hpc2.c | 48 +++++++++++++ arch/powerpc/boot/wrapper | 23 ++++++ 6 files changed, 151 insertions(+), 122 deletions(-) delete mode 100644 arch/powerpc/boot/cuboot-hpc2.c create mode 100644 arch/powerpc/boot/cuboot-mpc7448hpc2.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1348bbc92510..d21495f35727 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -438,25 +438,6 @@ config WANT_DEVICE_TREE bool default n -config DEVICE_TREE - string "Static device tree source file" - depends on WANT_DEVICE_TREE - help - This specifies the device tree source (.dts) file to be - compiled and included when building the bootwrapper. If a - relative filename is given, then it will be relative to - arch/powerpc/boot/dts. If you are not using the bootwrapper, - or do not need to build a dts into the bootwrapper, this - field is ignored. - - For example, this is required when building a cuImage target - for an older U-Boot, which cannot pass a device tree itself. - Such a kernel will not work with a newer U-Boot that tries to - pass a device tree (unless you tell it not to). If your U-Boot - does not mention a device tree in "help bootm", then use the - cuImage target and specify a device tree here. Otherwise, use - the uImage target and leave this field blank. - endmenu config ISA_DMA_API diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index f70df9b64f8f..6845482f0093 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -151,14 +151,11 @@ core-$(CONFIG_XMON) += arch/powerpc/xmon/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ # Default to zImage, override when needed -defaultimage-y := zImage -defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage -KBUILD_IMAGE := $(defaultimage-y) -all: $(KBUILD_IMAGE) +all: zImage CPPFLAGS_vmlinux.lds := -Upowerpc -BOOT_TARGETS = zImage zImage.initrd uImage +BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.% PHONY += $(BOOT_TARGETS) @@ -180,7 +177,7 @@ define archhelp endef install: vdso_install - $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install + $(Q)$(MAKE) $(build)=$(boot) install vdso_install: ifeq ($(CONFIG_PPC64),y) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 122a27078998..49797a45416c 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -60,8 +60,9 @@ src-wlib := string.S crt0.S stdio.c main.c \ src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \ ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \ - cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \ - fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \ + cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \ + cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \ + fixed-head.S ep88xc.c ep405.c \ cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \ cuboot-warp.c cuboot-85xx-cpm2.c src-boot := $(src-wlib) $(src-plat) empty.c @@ -123,6 +124,8 @@ targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a) extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds +dtstree := $(srctree)/$(src)/dts + wrapper :=$(srctree)/$(src)/wrapper wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \ $(wrapper) FORCE @@ -181,7 +184,7 @@ quiet_cmd_wrap = WRAP $@ image-$(CONFIG_PPC_PSERIES) += zImage.pseries image-$(CONFIG_PPC_MAPLE) += zImage.pseries image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries -image-$(CONFIG_PPC_PS3) += zImage.ps3 +image-$(CONFIG_PPC_PS3) += zImage-dtb.ps3 image-$(CONFIG_PPC_CELLEB) += zImage.pseries image-$(CONFIG_PPC_CHRP) += zImage.chrp image-$(CONFIG_PPC_EFIKA) += zImage.chrp @@ -191,33 +194,69 @@ image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800 image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage -ifneq ($(CONFIG_DEVICE_TREE),"") -image-$(CONFIG_PPC_8xx) += cuImage.8xx -image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc -image-$(CONFIG_EP405) += zImage.ep405 -image-$(CONFIG_8260) += cuImage.pq2 -image-$(CONFIG_EP8248E) += zImage.ep8248e -image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx -image-$(CONFIG_STORCENTER) += cuImage.824x -image-$(CONFIG_PPC_83xx) += cuImage.83xx -image-$(CONFIG_PPC_85xx) += cuImage.85xx -ifeq ($(CONFIG_CPM2),y) -image-$(CONFIG_PPC_85xx) += cuImage.85xx-cpm2 -endif -image-$(CONFIG_MPC7448HPC2) += cuImage.hpc2 +# +# Targets which embed a device tree blob +# +# Theses are default targets to build images which embed device tree blobs. +# They are only required on boards which do not have FDT support in firmware. +# Boards with newish u-boot firmare can use the uImage target above +# + +# Board ports in arch/powerpc/platform/40x/Kconfig +image-$(CONFIG_EP405) += zImage-dtb.ep405 +image-$(CONFIG_WALNUT) += treeImage.walnut + +# Board ports in arch/powerpc/platform/44x/Kconfig image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo image-$(CONFIG_SEQUOIA) += cuImage.sequoia image-$(CONFIG_RAINIER) += cuImage.rainier -image-$(CONFIG_WALNUT) += treeImage.walnut image-$(CONFIG_TAISHAN) += cuImage.taishan image-$(CONFIG_KATMAI) += cuImage.katmai image-$(CONFIG_WARP) += cuImage.warp -endif -ifneq ($(CONFIG_REDBOOT),"") -image-$(CONFIG_PPC_8xx) += zImage.redboot-8xx -endif +# Board ports in arch/powerpc/platform/8xx/Kconfig +image-$(CONFIG_PPC_MPC86XADS) += cuImage.mpc866ads +image-$(CONFIG_PPC_MPC885ADS) += cuImage.mpc885ads +image-$(CONFIG_PPC_EP88XC) += zImage-dtb.ep88xc +image-$(CONFIG_PPC_ADDER875) += cuImage.adder875-uboot \ + zImage-dtb.adder875-redboot + +# Board ports in arch/powerpc/platform/52xx/Kconfig +image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200 cuImage.lite5200b + +# Board ports in arch/powerpc/platform/82xx/Kconfig +image-$(CONFIG_MPC8272_ADS) += cuImage.mpc8272ads +image-$(CONFIG_PQ2FADS) += cuImage.pq2fads +image-$(CONFIG_EP8248E) += zImage-dtb.ep8248e + +# Board ports in arch/powerpc/platform/83xx/Kconfig +image-$(CONFIG_MPC832x_MDS) += cuImage.mpc832x_mds +image-$(CONFIG_MPC832x_RDB) += cuImage.mpc832x_rdb +image-$(CONFIG_MPC834x_ITX) += cuImage.mpc8349emitx \ + cuImage.mpc8349emitxgp +image-$(CONFIG_MPC834x_MDS) += cuImage.mpc834x_mds +image-$(CONFIG_MPC836x_MDS) += cuImage.mpc836x_mds + +# Board ports in arch/powerpc/platform/85xx/Kconfig +image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads +image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads +image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \ + cuImage.mpc8548cds \ + cuImage.mpc8555cds +image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds +image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ + cuImage.mpc8572ds +image-$(CONFIG_TQM8540) += cuImage.tqm8540 +image-$(CONFIG_TQM8541) += cuImage.tqm8541 +image-$(CONFIG_TQM8555) += cuImage.tqm8555 +image-$(CONFIG_TQM8560) += cuImage.tqm8560 +image-$(CONFIG_SBC8548) += cuImage.tqm8548 +image-$(CONFIG_SBC8560) += cuImage.tqm8560 + +# Board ports in arch/powerpc/platform/embedded6xx/Kconfig +image-$(CONFIG_STORCENTER) += cuImage.storcenter +image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2 # For 32-bit powermacs, build the COFF and miboot images # as well as the ELF images. @@ -233,24 +272,20 @@ targets += $(image-y) $(initrd-y) $(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz -# If CONFIG_WANT_DEVICE_TREE is set and CONFIG_DEVICE_TREE isn't an -# empty string, define 'dts' to be path to the dts -# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them -ifeq ($(CONFIG_WANT_DEVICE_TREE),y) -ifneq ($(CONFIG_DEVICE_TREE),"") -dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\ - ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%) -endif -endif - # Don't put the ramdisk on the pattern rule; when its missing make will try # the pattern rule with less dependencies that also matches (even with the # hard dependency listed). -$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts) - $(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz) +$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) + $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz) -$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts) - $(call if_changed,wrap,$*,$(dts)) +$(obj)/zImage.%: vmlinux $(wrapperbits) + $(call if_changed,wrap,$*) + +$(obj)/zImage-dtb.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts + $(call if_changed,wrap,$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz) + +$(obj)/zImage-dtb.%: vmlinux $(wrapperbits) $(dtstree)/%.dts + $(call if_changed,wrap,$*,$(dtstree)/$*.dts) # This cannot be in the root of $(src) as the zImage rule always adds a $(obj) # prefix @@ -260,24 +295,17 @@ $(obj)/vmlinux.strip: vmlinux $(obj)/zImage.iseries: vmlinux $(STRIP) -s -R .comment $< -o $@ -$(obj)/zImage.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts - $(STRIP) -s -R .comment $< -o vmlinux.strip - $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,) - -$(obj)/zImage.initrd.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts $(obj)/ramdisk.image.gz - $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,$(obj)/ramdisk.image.gz) - $(obj)/uImage: vmlinux $(wrapperbits) $(call if_changed,wrap,uboot) -$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits) - $(call if_changed,wrap,cuboot-$*,$(dts)) +$(obj)/cuImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits) + $(call if_changed,wrap,cuboot-$*,$(dtstree)/$*.dts) -$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits) - $(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz) +$(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits) + $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz) -$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits) - $(call if_changed,wrap,treeboot-$*,$(dts)) +$(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits) + $(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts) # If there isn't a platform selected then just strip the vmlinux. ifeq (,$(image-y)) diff --git a/arch/powerpc/boot/cuboot-hpc2.c b/arch/powerpc/boot/cuboot-hpc2.c deleted file mode 100644 index 1b8953259d75..000000000000 --- a/arch/powerpc/boot/cuboot-hpc2.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. - * - * Author: Roy Zang - * - * Description: - * Old U-boot compatibility for mpc7448hpc2 board - * Based on the code of Scott Wood - * for 83xx and 85xx. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include "ops.h" -#include "stdio.h" -#include "cuboot.h" - -#define TARGET_HAS_ETH1 -#include "ppcboot.h" - -static bd_t bd; -extern char _dtb_start[], _dtb_end[]; - -static void platform_fixups(void) -{ - void *tsi; - - dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); - dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); - dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); - tsi = find_node_by_devtype(NULL, "tsi-bridge"); - if (tsi) - setprop(tsi, "bus-frequency", &bd.bi_busfreq, - sizeof(bd.bi_busfreq)); -} - -void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - CUBOOT_INIT(); - fdt_init(_dtb_start); - serial_console_init(); - platform_ops.fixups = platform_fixups; -} diff --git a/arch/powerpc/boot/cuboot-mpc7448hpc2.c b/arch/powerpc/boot/cuboot-mpc7448hpc2.c new file mode 100644 index 000000000000..1b8953259d75 --- /dev/null +++ b/arch/powerpc/boot/cuboot-mpc7448hpc2.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Roy Zang + * + * Description: + * Old U-boot compatibility for mpc7448hpc2 board + * Based on the code of Scott Wood + * for 83xx and 85xx. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include "ops.h" +#include "stdio.h" +#include "cuboot.h" + +#define TARGET_HAS_ETH1 +#include "ppcboot.h" + +static bd_t bd; +extern char _dtb_start[], _dtb_end[]; + +static void platform_fixups(void) +{ + void *tsi; + + dt_fixup_memory(bd.bi_memstart, bd.bi_memsize); + dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr); + dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq); + tsi = find_node_by_devtype(NULL, "tsi-bridge"); + if (tsi) + setprop(tsi, "bus-frequency", &bd.bi_busfreq, + sizeof(bd.bi_busfreq)); +} + +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, + unsigned long r6, unsigned long r7) +{ + CUBOOT_INIT(); + fdt_init(_dtb_start); + serial_console_init(); + platform_ops.fixups = platform_fixups; +} diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 763a0c46f441..c3178155311b 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -158,6 +158,29 @@ miboot|uboot) cuboot*) binary=y gzip= + case "$platform" in + *-mpc885ads|*-adder875*|*-ep88xc) + platformo=$object/cuboot-8xx.o + ;; + *5200*|*-motionpro) + platformo=$object/cuboot-52xx.o + ;; + *-pq2fads|*-ep8248e|*-mpc8272*|*-storcenter) + platformo=$object/cuboot-pq2.o + ;; + *-mpc824*) + platformo=$object/cuboot-824x.o + ;; + *-mpc83*) + platformo=$object/cuboot-83xx.o + ;; + *-tqm8541|*-mpc8560*|*-tqm8560|*-tqm8555*) + platformo=$object/cuboot-85xx-cpm2.o + ;; + *-mpc85*) + platformo=$object/cuboot-85xx.o + ;; + esac ;; ps3) platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o" -- cgit v1.2.2 From a52572ddcd3d16cc5ccc9679bcbb7256d0ddad84 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 7 Feb 2008 07:37:26 +1100 Subject: [POWERPC] Update irq descriptor affinity The affinity mask in the virq descriptor needs to be set before we reset the affinity for the virq. Without doing this the call to get the new irq server fails and we end up leaving the virq pinned to the cpu we are removing. This does not fail the cpu remove from the kernel, but it does prevent cpu dlpar remove operations from returning the cpu to the hypervisor. Signed-off-by: Nathan Fontenot Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/xics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 8f8dd9c3ca6b..00e9d296118e 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -880,8 +880,8 @@ void xics_migrate_irqs_away(void) virq, cpu); /* Reset affinity to all cpus */ + irq_desc[virq].affinity = CPU_MASK_ALL; desc->chip->set_affinity(virq, CPU_MASK_ALL); - irq_desc[irq].affinity = CPU_MASK_ALL; unlock: spin_unlock_irqrestore(&desc->lock, flags); } -- cgit v1.2.2 From c3e8506c54f7263e71289e9e66533236d09f2fb7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 7 Feb 2008 07:37:31 +1100 Subject: [POWERPC] Split xics_teardown_cpu() This splits off the kexec path bits of the xics_teardown_cpu() routine into its own xics_kexec_teardown_cpu() routine. With the previous combined routine the CPPR for a cpu that is being removed may have its CPPR reset in the plpar_eoi() call (which explicitly sets the CPPR to a non-zero value). Splitting of the kexec bits of the code prevents this from happening in the cpu remove path. Once again, this does not cause the cpu remove from the kernel to fail, but it does cause cpu dlpar operations to not be able to return the cpu to the hypervisor. Signed-off-by: Nathan Fontenot Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/hotplug-cpu.c | 2 +- arch/powerpc/platforms/pseries/kexec.c | 2 +- arch/powerpc/platforms/pseries/xics.c | 14 ++++++++++---- arch/powerpc/platforms/pseries/xics.h | 3 ++- 4 files changed, 14 insertions(+), 7 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index c4ad54e0f288..1f032483c026 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void) { local_irq_disable(); idle_task_exit(); - xics_teardown_cpu(0); + xics_teardown_cpu(); unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow())); rtas_stop_self(); /* Should never get here... */ diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c index 412a5e7aff2d..e9dd5fe081c9 100644 --- a/arch/powerpc/platforms/pseries/kexec.c +++ b/arch/powerpc/platforms/pseries/kexec.c @@ -54,7 +54,7 @@ void __init setup_kexec_cpu_down_mpic(void) static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) { pseries_kexec_cpu_down(crash_shutdown, secondary); - xics_teardown_cpu(secondary); + xics_kexec_teardown_cpu(secondary); } void __init setup_kexec_cpu_down_xics(void) diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 00e9d296118e..485cb399b837 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -775,11 +775,9 @@ void xics_request_IPIs(void) } #endif /* CONFIG_SMP */ -void xics_teardown_cpu(int secondary) +void xics_teardown_cpu() { int cpu = smp_processor_id(); - unsigned int ipi; - struct irq_desc *desc; xics_set_cpu_priority(0); @@ -790,9 +788,17 @@ void xics_teardown_cpu(int secondary) lpar_qirr_info(cpu, 0xff); else direct_qirr_info(cpu, 0xff); +} + +void xics_kexec_teardown_cpu(int secondary) +{ + unsigned int ipi; + struct irq_desc *desc; + + xics_teardown_cpu(); /* - * we need to EOI the IPI if we got here from kexec down IPI + * we need to EOI the IPI * * probably need to check all the other interrupts too * should we be flagging idle loop instead? diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index 9ffd809d29e2..c26bcff47b6d 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h @@ -16,7 +16,8 @@ extern void xics_init_IRQ(void); extern void xics_setup_cpu(void); -extern void xics_teardown_cpu(int secondary); +extern void xics_teardown_cpu(void); +extern void xics_kexec_teardown_cpu(int secondary); extern void xics_cause_IPI(int cpu); extern void xics_request_IPIs(void); extern void xics_migrate_irqs_away(void); -- cgit v1.2.2 From b99e62608b5b9f8066629e7403a5f15401049b98 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 7 Feb 2008 07:37:35 +1100 Subject: [POWERPC] Remove redundant of_get_cpu_node routine It appears that xics.c has its own of_get_cpu_node(). Remove this and use the common one from prom.c. Signed-off-by: Nathan Fontenot Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/xics.c | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 485cb399b837..9ecf75fe9b14 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -658,31 +658,6 @@ static void __init xics_setup_8259_cascade(void) set_irq_chained_handler(cascade, pseries_8259_cascade); } -static struct device_node *cpuid_to_of_node(int cpu) -{ - struct device_node *np; - u32 hcpuid = get_hard_smp_processor_id(cpu); - - for_each_node_by_type(np, "cpu") { - int i, len; - const u32 *intserv; - - intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", - &len); - - if (!intserv) - intserv = of_get_property(np, "reg", &len); - - i = len / sizeof(u32); - - while (i--) - if (intserv[i] == hcpuid) - return np; - } - - return NULL; -} - void __init xics_init_IRQ(void) { int i, j; @@ -711,7 +686,7 @@ void __init xics_init_IRQ(void) xics_init_host(); /* Find the server numbers for the boot cpu. */ - np = cpuid_to_of_node(boot_cpuid); + np = of_get_cpu_node(boot_cpuid, NULL); BUG_ON(!np); ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); if (!ireg) -- cgit v1.2.2 From de0723dcca6e593a12a259798a54eb0e82628fb8 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Thu, 7 Feb 2008 07:37:40 +1100 Subject: [POWERPC] Update default irq servers when boot cpu is removed The xics code does update the default server information when the boot cpu is removed. This patch recognizes when the boot cpu is being removed and updates the appropriate information based on the new 'boot cpu'. Failure to update this information can causes us to leave irqs pinned to cpus that are being removed, especially when removing the boot cpu. The cpu is removed from the kernel, but cpu dlpar remove operations fail since we cannot return the cpu to the hypervisor. Signed-off-by: Nathan Fonteno Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/xics.c | 77 ++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 9ecf75fe9b14..ca52b587166d 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value) /* High level handlers and init code */ +static void xics_update_irq_servers(void) +{ + int i, j; + struct device_node *np; + u32 ilen; + const u32 *ireg, *isize; + u32 hcpuid; + + /* Find the server numbers for the boot cpu. */ + np = of_get_cpu_node(boot_cpuid, NULL); + BUG_ON(!np); + + ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); + if (!ireg) { + of_node_put(np); + return; + } + + i = ilen / sizeof(int); + hcpuid = get_hard_smp_processor_id(boot_cpuid); + + /* Global interrupt distribution server is specified in the last + * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last + * entry fom this property for current boot cpu id and use it as + * default distribution server + */ + for (j = 0; j < i; j += 2) { + if (ireg[j] == hcpuid) { + default_server = hcpuid; + default_distrib_server = ireg[j+1]; + + isize = of_get_property(np, + "ibm,interrupt-server#-size", NULL); + if (isize) + interrupt_server_size = *isize; + } + } + + of_node_put(np); +} #ifdef CONFIG_SMP static int get_irq_server(unsigned int virq, unsigned int strict_check) @@ -169,6 +209,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) cpumask_t cpumask = irq_desc[virq].affinity; cpumask_t tmp = CPU_MASK_NONE; + if (! cpu_isset(default_server, cpu_online_map)) + xics_update_irq_servers(); + if (!distribute_irqs) return default_server; @@ -660,12 +703,9 @@ static void __init xics_setup_8259_cascade(void) void __init xics_init_IRQ(void) { - int i, j; struct device_node *np; - u32 ilen, indx = 0; - const u32 *ireg, *isize; + u32 indx = 0; int found = 0; - u32 hcpuid; ppc64_boot_msg(0x20, "XICS Init"); @@ -684,34 +724,7 @@ void __init xics_init_IRQ(void) return; xics_init_host(); - - /* Find the server numbers for the boot cpu. */ - np = of_get_cpu_node(boot_cpuid, NULL); - BUG_ON(!np); - ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); - if (!ireg) - goto skip_gserver_check; - i = ilen / sizeof(int); - hcpuid = get_hard_smp_processor_id(boot_cpuid); - - /* Global interrupt distribution server is specified in the last - * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last - * entry fom this property for current boot cpu id and use it as - * default distribution server - */ - for (j = 0; j < i; j += 2) { - if (ireg[j] == hcpuid) { - default_server = hcpuid; - default_distrib_server = ireg[j+1]; - - isize = of_get_property(np, - "ibm,interrupt-server#-size", NULL); - if (isize) - interrupt_server_size = *isize; - } - } -skip_gserver_check: - of_node_put(np); + xics_update_irq_servers(); if (firmware_has_feature(FW_FEATURE_LPAR)) ppc_md.get_irq = xics_get_irq_lpar; -- cgit v1.2.2 From fde9d16faee27907852b59e7c0cd0741975c37eb Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 6 Feb 2008 07:04:58 -0600 Subject: [POWERPC] 4xx: Fix Walnut build The addition of of_rtc for the Walnut board was only half complete. Select OF_RTC in the Kconfig and include the appropriate header to make it compile. Signed-off-by: Josh Boyer --- arch/powerpc/platforms/40x/Kconfig | 1 + arch/powerpc/platforms/40x/walnut.c | 1 + 2 files changed, 2 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 74f31177e47a..a9260e21451e 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -72,6 +72,7 @@ config WALNUT default y select 405GP select PCI + select OF_RTC help This option enables support for the IBM PPC405GP evaluation board. diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c index 5d9edd917f92..b8b257efeb77 100644 --- a/arch/powerpc/platforms/40x/walnut.c +++ b/arch/powerpc/platforms/40x/walnut.c @@ -18,6 +18,7 @@ #include #include +#include #include #include -- cgit v1.2.2 From 3c0c6cb5eb2931712d5d750bf27d27d37a44d75e Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 25 Sep 2007 05:29:52 +1000 Subject: [POWERPC] 4xx: Add 440EPx Sequoia ehci dts entry Adds USB EHCI entry to PowerPC 440EPx Sequoia DTS. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/boot/dts/sequoia.dts | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts index d9046c1adcbe..5c13d46f441d 100644 --- a/arch/powerpc/boot/dts/sequoia.dts +++ b/arch/powerpc/boot/dts/sequoia.dts @@ -138,6 +138,14 @@ interrupts = <15 8>; }; + USB0: ehci@e0000300 { + compatible = "ibm,usb-ehci-440epx", "usb-ehci"; + interrupt-parent = <&UIC0>; + interrupts = <1a 4>; + reg = <0 e0000300 90 0 e0000390 70>; + big-endian; + }; + POB0: opb { compatible = "ibm,opb-440epx", "ibm,opb"; #address-cells = <1>; -- cgit v1.2.2 From c41f4af8fef6ef5bec7c9d2335ba19636058d2a7 Mon Sep 17 00:00:00 2001 From: Sean MacLennan Date: Sat, 26 Jan 2008 16:39:39 +1100 Subject: [POWERPC] 4xx: Fix offset value on Warp board While merging, I found a small bug that I forgot to send. I add an offset to a value twice. Signed-off-by: Sean MacLennan Signed-off-by: Josh Boyer --- arch/powerpc/platforms/44x/warp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c index 8f01563dbd2a..da5b7b7599db 100644 --- a/arch/powerpc/platforms/44x/warp.c +++ b/arch/powerpc/platforms/44x/warp.c @@ -137,7 +137,7 @@ static int __init pika_dtm_start(void) } of_node_put(np); - fpga = ioremap(res.start + 0x20, 4); + fpga = ioremap(res.start, 0x24); if (fpga == NULL) return -ENOENT; -- cgit v1.2.2 From 853265e588153dca22c82b84df39bbb40abd7ad0 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Tue, 5 Feb 2008 01:57:55 +1100 Subject: [POWERPC] Add missing native dcr dcr_ind_lock spinlock The include/asm-powerpc/dcr-native.h declares extern spinlock_t dcr_ind_lock; but it's actually isn't defined. This patch adds a missing dcr_ind_lock. Signed-off-by: Valentine Barshak Signed-off-by: Josh Boyer --- arch/powerpc/sysdev/dcr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c index 427027c7ea0f..437e48d3ae33 100644 --- a/arch/powerpc/sysdev/dcr.c +++ b/arch/powerpc/sysdev/dcr.c @@ -137,5 +137,6 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_c) h.token = NULL; } EXPORT_SYMBOL_GPL(dcr_unmap); - -#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */ +#else /* defined(CONFIG_PPC_DCR_NATIVE) */ +DEFINE_SPINLOCK(dcr_ind_lock); +#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */ -- cgit v1.2.2 From f65255e8d51ecbc6c9eef20d39e0377d19b658ca Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:34 -0800 Subject: [POWERPC] Use user_regset accessors for FP regs This implements user_regset-style accessors for the powerpc FPU data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8b056d2295cc..f1ce64649256 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -103,24 +104,48 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) } +static int fpr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + flush_fp_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != + offsetof(struct thread_struct, fpr[32])); + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.fpr, 0, -1); +} + +static int fpr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + flush_fp_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != + offsetof(struct thread_struct, fpr[32])); + + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpr, 0, -1); +} + static int get_fpregs(void __user *data, struct task_struct *task, int has_fpscr) { unsigned int count = has_fpscr ? 33 : 32; - - if (copy_to_user(data, task->thread.fpr, count * sizeof(double))) + if (!access_ok(VERIFY_WRITE, data, count * sizeof(double))) return -EFAULT; - return 0; + return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data); } static int set_fpregs(void __user *data, struct task_struct *task, int has_fpscr) { unsigned int count = has_fpscr ? 33 : 32; - - if (copy_from_user(task->thread.fpr, data, count * sizeof(double))) + if (!access_ok(VERIFY_READ, data, count * sizeof(double))) return -EFAULT; - return 0; + return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data); } -- cgit v1.2.2 From 3caf06c6e0656b25f694e3d414191cedcecf76ce Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:39 -0800 Subject: [POWERPC] Use user_regset accessors for altivec regs This implements user_regset-style accessors for the powerpc Altivec data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 112 ++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 34 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index f1ce64649256..7cdf35a7c833 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -163,30 +164,87 @@ static int set_fpregs(void __user *data, struct task_struct *task, * (combined (32- and 64-bit) gdb. */ +static int vr_active(struct task_struct *target, + const struct user_regset *regset) +{ + flush_altivec_to_thread(target); + return target->thread.used_vr ? regset->n : 0; +} + +static int vr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + flush_altivec_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, vscr) != + offsetof(struct thread_struct, vr[32])); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.vr, 0, + 33 * sizeof(vector128)); + if (!ret) { + /* + * Copy out only the low-order word of vrsave. + */ + union { + elf_vrreg_t reg; + u32 word; + } vrsave; + memset(&vrsave, 0, sizeof(vrsave)); + vrsave.word = target->thread.vrsave; + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave, + 33 * sizeof(vector128), -1); + } + + return ret; +} + +static int vr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + + flush_altivec_to_thread(target); + + BUILD_BUG_ON(offsetof(struct thread_struct, vscr) != + offsetof(struct thread_struct, vr[32])); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.vr, 0, 33 * sizeof(vector128)); + if (!ret && count > 0) { + /* + * We use only the first word of vrsave. + */ + union { + elf_vrreg_t reg; + u32 word; + } vrsave; + memset(&vrsave, 0, sizeof(vrsave)); + vrsave.word = target->thread.vrsave; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave, + 33 * sizeof(vector128), -1); + if (!ret) + target->thread.vrsave = vrsave.word; + } + + return ret; +} + /* * Get contents of AltiVec register state in task TASK */ static int get_vrregs(unsigned long __user *data, struct task_struct *task) { - unsigned long regsize; - - /* copy AltiVec registers VR[0] .. VR[31] */ - regsize = 32 * sizeof(vector128); - if (copy_to_user(data, task->thread.vr, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VSCR */ - regsize = 1 * sizeof(vector128); - if (copy_to_user(data, &task->thread.vscr, regsize)) + if (!access_ok(VERIFY_WRITE, data, + 33 * sizeof(vector128) + sizeof(u32))) return -EFAULT; - data += (regsize / sizeof(unsigned long)); - /* copy VRSAVE */ - if (put_user(task->thread.vrsave, (u32 __user *)data)) - return -EFAULT; - - return 0; + return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), + NULL, data); } /* @@ -194,25 +252,11 @@ static int get_vrregs(unsigned long __user *data, struct task_struct *task) */ static int set_vrregs(struct task_struct *task, unsigned long __user *data) { - unsigned long regsize; - - /* copy AltiVec registers VR[0] .. VR[31] */ - regsize = 32 * sizeof(vector128); - if (copy_from_user(task->thread.vr, data, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VSCR */ - regsize = 1 * sizeof(vector128); - if (copy_from_user(&task->thread.vscr, data, regsize)) - return -EFAULT; - data += (regsize / sizeof(unsigned long)); - - /* copy VRSAVE */ - if (get_user(task->thread.vrsave, (u32 __user *)data)) + if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32))) return -EFAULT; - return 0; + return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), + NULL, data); } #endif /* CONFIG_ALTIVEC */ -- cgit v1.2.2 From a4e4b175b6028ebfb2217e0ca1fa0487dc73ccc4 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:48 -0800 Subject: [POWERPC] Use user_regset accessors for SPE regs This implements user_regset-style accessors for the powerpc SPE data, and rewrites the existing ptrace code in terms of those calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 90 ++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 33 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7cdf35a7c833..8c25b0033650 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -272,55 +272,79 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data) * } */ -/* - * Get contents of SPE register state in task TASK. - */ -static int get_evrregs(unsigned long *data, struct task_struct *task) +static int evr_active(struct task_struct *target, + const struct user_regset *regset) { - int i; + flush_spe_to_thread(target); + return target->thread.used_spe ? regset->n : 0; +} - if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long))) - return -EFAULT; +static int evr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; - /* copy SPEFSCR */ - if (__put_user(task->thread.spefscr, &data[34])) - return -EFAULT; + flush_spe_to_thread(target); - /* copy SPE registers EVR[0] .. EVR[31] */ - for (i = 0; i < 32; i++, data++) - if (__put_user(task->thread.evr[i], data)) - return -EFAULT; + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.evr, + 0, sizeof(target->thread.evr)); - /* copy ACC */ - if (__put_user64(task->thread.acc, (unsigned long long *)data)) - return -EFAULT; + BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) != + offsetof(struct thread_struct, spefscr)); - return 0; + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.acc, + sizeof(target->thread.evr), -1); + + return ret; +} + +static int evr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + + flush_spe_to_thread(target); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.evr, + 0, sizeof(target->thread.evr)); + + BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) != + offsetof(struct thread_struct, spefscr)); + + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.acc, + sizeof(target->thread.evr), -1); + + return ret; } /* - * Write contents of SPE register state into task TASK. + * Get contents of SPE register state in task TASK. */ -static int set_evrregs(struct task_struct *task, unsigned long *data) +static int get_evrregs(unsigned long __user *data, struct task_struct *task) { - int i; - - if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long))) + if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32))) return -EFAULT; - /* copy SPEFSCR */ - if (__get_user(task->thread.spefscr, &data[34])) - return -EFAULT; + return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data); +} - /* copy SPE registers EVR[0] .. EVR[31] */ - for (i = 0; i < 32; i++, data++) - if (__get_user(task->thread.evr[i], data)) - return -EFAULT; - /* copy ACC */ - if (__get_user64(task->thread.acc, (unsigned long long*)data)) +/* + * Write contents of SPE register state into task TASK. + */ +static int set_evrregs(struct task_struct *task, unsigned long *data) +{ + if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32))) return -EFAULT; - return 0; + return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data); } #endif /* CONFIG_SPE */ -- cgit v1.2.2 From 26f7713020129e556e494fd36b2db1e651e33ba3 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:51 -0800 Subject: [POWERPC] ptrace accessors for special regs MSR and TRAP This isolates the ptrace code for the special-case registers msr and trap from the ptrace-layout dispatch code. This should inline away completely. It cleanly separates the low-level machine magic that has to be done for deep reasons, from the superficial details of the ptrace interface. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 45 +++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 8c25b0033650..4edc1186f6ac 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -60,20 +60,38 @@ #define PT_MAX_PUT_REG PT_CCR #endif +static unsigned long get_user_msr(struct task_struct *task) +{ + return task->thread.regs->msr | task->thread.fpexc_mode; +} + +static int set_user_msr(struct task_struct *task, unsigned long msr) +{ + task->thread.regs->msr &= ~MSR_DEBUGCHANGE; + task->thread.regs->msr |= msr & MSR_DEBUGCHANGE; + return 0; +} + +/* + * We prevent mucking around with the reserved area of trap + * which are used internally by the kernel. + */ +static int set_user_trap(struct task_struct *task, unsigned long trap) +{ + task->thread.regs->trap = trap & 0xfff0; + return 0; +} + /* * Get contents of register REGNO in task TASK. */ unsigned long ptrace_get_reg(struct task_struct *task, int regno) { - unsigned long tmp = 0; - if (task->thread.regs == NULL) return -EIO; - if (regno == PT_MSR) { - tmp = ((unsigned long *)task->thread.regs)[PT_MSR]; - return tmp | task->thread.fpexc_mode; - } + if (regno == PT_MSR) + return get_user_msr(task); if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) return ((unsigned long *)task->thread.regs)[regno]; @@ -89,15 +107,12 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) if (task->thread.regs == NULL) return -EIO; - if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) { - if (regno == PT_MSR) - data = (data & MSR_DEBUGCHANGE) - | (task->thread.regs->msr & ~MSR_DEBUGCHANGE); - /* We prevent mucking around with the reserved area of trap - * which are used internally by the kernel - */ - if (regno == PT_TRAP) - data &= 0xfff0; + if (regno == PT_MSR) + return set_user_msr(task, data); + if (regno == PT_TRAP) + return set_user_trap(task, data); + + if (regno <= PT_MAX_PUT_REG) { ((unsigned long *)task->thread.regs)[regno] = data; return 0; } -- cgit v1.2.2 From 44dd3f50d3848e332b49e83a142b39b960ec962e Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:57:55 -0800 Subject: [POWERPC] Use user_regset accessors for GPRs This implements user_regset-style accessors for the powerpc general registers. In the future these functions will be the only place that needs to understand the user_regset layout (core dump format) and how it maps to the internal representation of user thread state. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 4edc1186f6ac..d9b952faee73 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -119,6 +119,97 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data) return -EIO; } +static int gpr_get(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + int ret; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + target->thread.regs, + 0, offsetof(struct pt_regs, msr)); + if (!ret) { + unsigned long msr = get_user_msr(target); + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr, + offsetof(struct pt_regs, msr), + offsetof(struct pt_regs, msr) + + sizeof(msr)); + } + + BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != + offsetof(struct pt_regs, msr) + sizeof(long)); + + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &target->thread.regs->orig_gpr3, + offsetof(struct pt_regs, orig_gpr3), + sizeof(struct pt_regs)); + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(struct pt_regs), -1); + + return ret; +} + +static int gpr_set(struct task_struct *target, const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long reg; + int ret; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + target->thread.regs, + 0, PT_MSR * sizeof(reg)); + + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, + PT_MSR * sizeof(reg), + (PT_MSR + 1) * sizeof(reg)); + if (!ret) + ret = set_user_msr(target, reg); + } + + BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != + offsetof(struct pt_regs, msr) + sizeof(long)); + + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.regs->orig_gpr3, + PT_ORIG_R3 * sizeof(reg), + (PT_MAX_PUT_REG + 1) * sizeof(reg)); + + if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret) + ret = user_regset_copyin_ignore( + &pos, &count, &kbuf, &ubuf, + (PT_MAX_PUT_REG + 1) * sizeof(reg), + PT_TRAP * sizeof(reg)); + + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®, + PT_TRAP * sizeof(reg), + (PT_TRAP + 1) * sizeof(reg)); + if (!ret) + ret = set_user_trap(target, reg); + } + + if (!ret) + ret = user_regset_copyin_ignore( + &pos, &count, &kbuf, &ubuf, + (PT_TRAP + 1) * sizeof(reg), -1); + + return ret; +} static int fpr_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, -- cgit v1.2.2 From 80fdf4709497a276a826c9d8426ef1effc8f8e33 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:00 -0800 Subject: [POWERPC] Add user_regset_view definitions This provides the task_user_regset_view entry point and support for all the native-mode (64 on CONFIG_PPC64, 32 on CONFIG_PPC32) thread register state. This will enable generic machine-independent code to access user-mode threads' registers for debugging and dumping. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/Makefile | 2 ++ arch/powerpc/kernel/ptrace.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 58dbfeff9b4d..ac07112b65de 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -2,6 +2,8 @@ # Makefile for the linux kernel. # +CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' + ifeq ($(CONFIG_PPC64),y) CFLAGS_prom_init.o += -mno-minimal-toc endif diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index d9b952faee73..eb00274e84ba 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -455,6 +455,58 @@ static int set_evrregs(struct task_struct *task, unsigned long *data) #endif /* CONFIG_SPE */ +/* + * These are our native regset flavors. + */ +enum powerpc_regset { + REGSET_GPR, + REGSET_FPR, +#ifdef CONFIG_ALTIVEC + REGSET_VMX, +#endif +#ifdef CONFIG_SPE + REGSET_SPE, +#endif +}; + +static const struct user_regset native_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, + .size = sizeof(long), .align = sizeof(long), + .get = gpr_get, .set = gpr_set + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, + .size = sizeof(double), .align = sizeof(double), + .get = fpr_get, .set = fpr_set + }, +#ifdef CONFIG_ALTIVEC + [REGSET_VMX] = { + .core_note_type = NT_PPC_VMX, .n = 34, + .size = sizeof(vector128), .align = sizeof(vector128), + .active = vr_active, .get = vr_get, .set = vr_set + }, +#endif +#ifdef CONFIG_SPE + [REGSET_SPE] = { + .n = 35, + .size = sizeof(u32), .align = sizeof(u32), + .active = evr_active, .get = evr_get, .set = evr_set + }, +#endif +}; + +static const struct user_regset_view user_ppc_native_view = { + .name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, + .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_ppc_native_view; +} + + void user_enable_single_step(struct task_struct *task) { struct pt_regs *regs = task->thread.regs; -- cgit v1.2.2 From fa8f5cb0c980e9fe3e04bc937fbd13417b52c046 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:08 -0800 Subject: [POWERPC] Add user_regset compat support This extends task_user_regset_view CONFIG_PPC64 with support for the 32-bit view of register state, compatible with what a CONFIG_PPC32 kernel provides. This will enable generic machine-independent code to access user-mode threads' registers for debugging and dumping. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 162 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index eb00274e84ba..60de9ee3701d 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -501,8 +501,170 @@ static const struct user_regset_view user_ppc_native_view = { .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets) }; +#ifdef CONFIG_PPC64 +#include + +static int gpr32_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const unsigned long *regs = &target->thread.regs->gpr[0]; + compat_ulong_t *k = kbuf; + compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) + for (; count > 0 && pos < PT_MSR; --count) + *k++ = regs[pos++]; + else + for (; count > 0 && pos < PT_MSR; --count) + if (__put_user((compat_ulong_t) regs[pos++], u++)) + return -EFAULT; + + if (count > 0 && pos == PT_MSR) { + reg = get_user_msr(target); + if (kbuf) + *k++ = reg; + else if (__put_user(reg, u++)) + return -EFAULT; + ++pos; + --count; + } + + if (kbuf) + for (; count > 0 && pos < PT_REGS_COUNT; --count) + *k++ = regs[pos++]; + else + for (; count > 0 && pos < PT_REGS_COUNT; --count) + if (__put_user((compat_ulong_t) regs[pos++], u++)) + return -EFAULT; + + kbuf = k; + ubuf = u; + pos *= sizeof(reg); + count *= sizeof(reg); + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + PT_REGS_COUNT * sizeof(reg), -1); +} + +static int gpr32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *regs = &target->thread.regs->gpr[0]; + const compat_ulong_t *k = kbuf; + const compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target->thread.regs == NULL) + return -EIO; + + CHECK_FULL_REGS(target->thread.regs); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) + for (; count > 0 && pos < PT_MSR; --count) + regs[pos++] = *k++; + else + for (; count > 0 && pos < PT_MSR; --count) { + if (__get_user(reg, u++)) + return -EFAULT; + regs[pos++] = reg; + } + + + if (count > 0 && pos == PT_MSR) { + if (kbuf) + reg = *k++; + else if (__get_user(reg, u++)) + return -EFAULT; + set_user_msr(target, reg); + ++pos; + --count; + } + + if (kbuf) + for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) + regs[pos++] = *k++; + else + for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) { + if (__get_user(reg, u++)) + return -EFAULT; + regs[pos++] = reg; + } + + if (count > 0 && pos == PT_TRAP) { + if (kbuf) + reg = *k++; + else if (__get_user(reg, u++)) + return -EFAULT; + set_user_trap(target, reg); + ++pos; + --count; + } + + kbuf = k; + ubuf = u; + pos *= sizeof(reg); + count *= sizeof(reg); + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + (PT_TRAP + 1) * sizeof(reg), -1); +} + +/* + * These are the regset flavors matching the CONFIG_PPC32 native set. + */ +static const struct user_regset compat_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, .n = ELF_NGREG, + .size = sizeof(compat_long_t), .align = sizeof(compat_long_t), + .get = gpr32_get, .set = gpr32_set + }, + [REGSET_FPR] = { + .core_note_type = NT_PRFPREG, .n = ELF_NFPREG, + .size = sizeof(double), .align = sizeof(double), + .get = fpr_get, .set = fpr_set + }, +#ifdef CONFIG_ALTIVEC + [REGSET_VMX] = { + .core_note_type = NT_PPC_VMX, .n = 34, + .size = sizeof(vector128), .align = sizeof(vector128), + .active = vr_active, .get = vr_get, .set = vr_set + }, +#endif +#ifdef CONFIG_SPE + [REGSET_SPE] = { + .n = 35, + .size = sizeof(u32), .align = sizeof(u32), + .active = evr_active, .get = evr_get, .set = evr_set + }, +#endif +}; + +static const struct user_regset_view user_ppc_compat_view = { + .name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI, + .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets) +}; +#endif /* CONFIG_PPC64 */ + const struct user_regset_view *task_user_regset_view(struct task_struct *task) { +#ifdef CONFIG_PPC64 + if (test_tsk_thread_flag(task, TIF_32BIT)) + return &user_ppc_compat_view; +#endif return &user_ppc_native_view; } -- cgit v1.2.2 From 01e31dbabc020bf82e7e5359c031a550daafb8ff Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 2 Jan 2008 17:03:11 -0800 Subject: [POWERPC] Switch to generic compat_binfmt_elf code This switches the CONFIG_PPC64 support for 32-bit ELF to use the generic fs/compat_binfmt_elf.c implementation instead of our own binfmt_elf32.c. Since so much is the same between 32/64, there is only one macro we have to define to make the generic support work out of the box. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/Makefile | 2 +- arch/powerpc/kernel/binfmt_elf32.c | 69 -------------------------------------- 3 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 arch/powerpc/kernel/binfmt_elf32.c (limited to 'arch/powerpc') diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d21495f35727..8dcac0b22d68 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -97,6 +97,7 @@ config EARLY_PRINTK config COMPAT bool default y if PPC64 + select COMPAT_BINFMT_ELF config SYSVIPC_COMPAT bool diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ac07112b65de..0662ae46f724 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -17,7 +17,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ init_task.o process.o systbl.o idle.o \ signal.o obj-y += vdso32/ -obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ +obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o cpu_setup_ppc970.o \ cpu_setup_pa6t.o \ diff --git a/arch/powerpc/kernel/binfmt_elf32.c b/arch/powerpc/kernel/binfmt_elf32.c deleted file mode 100644 index 1d45d7782d4e..000000000000 --- a/arch/powerpc/kernel/binfmt_elf32.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons. - * based on the SPARC64 version. - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) - * - * Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp - * Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#undef ELF_ARCH -#undef ELF_CLASS -#define ELF_CLASS ELFCLASS32 -#define ELF_ARCH EM_PPC - -#undef elfhdr -#undef elf_phdr -#undef elf_note -#undef elf_addr_t -#define elfhdr elf32_hdr -#define elf_phdr elf32_phdr -#define elf_note elf32_note -#define elf_addr_t Elf32_Off - -#define elf_prstatus compat_elf_prstatus -#define elf_prpsinfo compat_elf_prpsinfo - -#define elf_core_copy_regs compat_elf_core_copy_regs -static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs, - struct pt_regs *regs) -{ - PPC_ELF_CORE_COPY_REGS((*elf_regs), regs); -} - -#define elf_core_copy_task_regs compat_elf_core_copy_task_regs -static int compat_elf_core_copy_task_regs(struct task_struct *tsk, - compat_elf_gregset_t *elf_regs) -{ - struct pt_regs *regs = tsk->thread.regs; - if (regs) - compat_elf_core_copy_regs(elf_regs, regs); - return 1; -} - -#include - -#undef cputime_to_timeval -#define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void -cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) -{ - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; -} - -#define init_elf_binfmt init_elf32_binfmt - -#include "../../../fs/binfmt_elf.c" -- cgit v1.2.2 From c391cd0093a2c86a6d1bc256198caad29fff0f60 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:36 -0800 Subject: [POWERPC] Use regset code for PTRACE_*REGS* requests This replaces all the code for powerpc PTRACE_*REGS* requests with simple calls to copy_regset_from_user and copy_regset_to_user. All the ptrace formats are either the whole corresponding user_regset format (core dump format) or a leading subset of it, so we can get rid of all the remaining embedded knowledge of both those layouts and of the internal data structures they correspond to. Only the user_regset accessors need to implement that. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 234 +++++++++++-------------------------------- 1 file changed, 59 insertions(+), 175 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 60de9ee3701d..2c1ee2cf9419 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -237,24 +237,6 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, &target->thread.fpr, 0, -1); } -static int get_fpregs(void __user *data, struct task_struct *task, - int has_fpscr) -{ - unsigned int count = has_fpscr ? 33 : 32; - if (!access_ok(VERIFY_WRITE, data, count * sizeof(double))) - return -EFAULT; - return fpr_get(task, NULL, 0, count * sizeof(double), NULL, data); -} - -static int set_fpregs(void __user *data, struct task_struct *task, - int has_fpscr) -{ - unsigned int count = has_fpscr ? 33 : 32; - if (!access_ok(VERIFY_READ, data, count * sizeof(double))) - return -EFAULT; - return fpr_set(task, NULL, 0, count * sizeof(double), NULL, data); -} - #ifdef CONFIG_ALTIVEC /* @@ -339,31 +321,6 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, return ret; } - -/* - * Get contents of AltiVec register state in task TASK - */ -static int get_vrregs(unsigned long __user *data, struct task_struct *task) -{ - if (!access_ok(VERIFY_WRITE, data, - 33 * sizeof(vector128) + sizeof(u32))) - return -EFAULT; - - return vr_get(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), - NULL, data); -} - -/* - * Write contents of AltiVec register state into task TASK. - */ -static int set_vrregs(struct task_struct *task, unsigned long __user *data) -{ - if (!access_ok(VERIFY_READ, data, 33 * sizeof(vector128) + sizeof(u32))) - return -EFAULT; - - return vr_set(task, NULL, 0, 33 * sizeof(vector128) + sizeof(u32), - NULL, data); -} #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SPE @@ -430,28 +387,6 @@ static int evr_set(struct task_struct *target, const struct user_regset *regset, return ret; } - -/* - * Get contents of SPE register state in task TASK. - */ -static int get_evrregs(unsigned long __user *data, struct task_struct *task) -{ - if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(u32))) - return -EFAULT; - - return evr_get(task, NULL, 0, 35 * sizeof(u32), NULL, data); -} - -/* - * Write contents of SPE register state into task TASK. - */ -static int set_evrregs(struct task_struct *task, unsigned long *data) -{ - if (!access_ok(VERIFY_READ, data, 35 * sizeof(u32))) - return -EFAULT; - - return evr_set(task, NULL, 0, 35 * sizeof(u32), NULL, data); -} #endif /* CONFIG_SPE */ @@ -736,55 +671,29 @@ void ptrace_disable(struct task_struct *child) static long arch_ptrace_old(struct task_struct *child, long request, long addr, long data) { - int ret = -EPERM; - - switch(request) { - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned long __user *tmp = (unsigned long __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */ - flush_fp_to_thread(child); - ret = get_fpregs((void __user *)addr, child, 0); - break; - } - - case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */ - flush_fp_to_thread(child); - ret = set_fpregs((void __user *)addr, child, 0); - break; + switch (request) { + case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_GPR, 0, 32 * sizeof(long), + (void __user *) data); + + case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_GPR, 0, 32 * sizeof(long), + (const void __user *) data); + + case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_FPR, 0, 32 * sizeof(double), + (void __user *) data); + + case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_FPR, 0, 32 * sizeof(double), + (const void __user *) data); } - } - return ret; + return -EPERM; } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -875,85 +784,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef CONFIG_PPC64 case PTRACE_GETREGS64: #endif - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ - int ui; - if (!access_ok(VERIFY_WRITE, (void __user *)data, - sizeof(struct pt_regs))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret |= __put_user(ptrace_get_reg(child, ui), - (unsigned long __user *) data); - data += sizeof(long); - } - break; - } + case PTRACE_GETREGS: /* Get all pt_regs from the child. */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_GPR, + 0, sizeof(struct pt_regs), + (void __user *) data); #ifdef CONFIG_PPC64 case PTRACE_SETREGS64: #endif - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - unsigned long tmp; - int ui; - if (!access_ok(VERIFY_READ, (void __user *)data, - sizeof(struct pt_regs))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret = __get_user(tmp, (unsigned long __user *) data); - if (ret) - break; - ptrace_put_reg(child, ui, tmp); - data += sizeof(long); - } - break; - } - - case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */ - flush_fp_to_thread(child); - ret = get_fpregs((void __user *)data, child, 1); - break; - } - - case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */ - flush_fp_to_thread(child); - ret = set_fpregs((void __user *)data, child, 1); - break; - } + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_GPR, + 0, sizeof(struct pt_regs), + (const void __user *) data); + + case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_FPR, + 0, sizeof(elf_fpregset_t), + (void __user *) data); + + case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_FPR, + 0, sizeof(elf_fpregset_t), + (const void __user *) data); #ifdef CONFIG_ALTIVEC case PTRACE_GETVRREGS: - /* Get the child altivec register state. */ - flush_altivec_to_thread(child); - ret = get_vrregs((unsigned long __user *)data, child); - break; + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_VMX, + 0, (33 * sizeof(vector128) + + sizeof(u32)), + (void __user *) data); case PTRACE_SETVRREGS: - /* Set the child altivec register state. */ - flush_altivec_to_thread(child); - ret = set_vrregs(child, (unsigned long __user *)data); - break; + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_VMX, + 0, (33 * sizeof(vector128) + + sizeof(u32)), + (const void __user *) data); #endif #ifdef CONFIG_SPE case PTRACE_GETEVRREGS: /* Get the child spe register state. */ - flush_spe_to_thread(child); - ret = get_evrregs((unsigned long __user *)data, child); - break; + return copy_regset_to_user(child, &user_ppc_native_view, + REGSET_SPE, 0, 35 * sizeof(u32), + (void __user *) data); case PTRACE_SETEVRREGS: /* Set the child spe register state. */ - /* this is to clear the MSR_SPE bit to force a reload - * of register state from memory */ - flush_spe_to_thread(child); - ret = set_evrregs(child, (unsigned long __user *)data); - break; + return copy_regset_from_user(child, &user_ppc_native_view, + REGSET_SPE, 0, 35 * sizeof(u32), + (const void __user *) data); #endif /* Old reverse args ptrace callss */ -- cgit v1.2.2 From c034243504b8396c4293abdc63aa3fc336a7d870 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:40 -0800 Subject: [POWERPC] Use generic ptrace peekdata/pokedata Now that ptrace_request handles these, we can drop some more boilerplate. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 2c1ee2cf9419..7571c2e2d991 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -701,12 +701,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) int ret = -EPERM; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsigned long index, tmp; @@ -734,12 +728,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - /* write the word at location addr in the USER area */ case PTRACE_POKEUSR: { unsigned long index; -- cgit v1.2.2 From 1d48d71c06172c0853e04c334456e64cc006e208 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:49 -0800 Subject: [POWERPC] Use generic compat_ptrace_request This removes some duplicated code by calling the new generic compat_ptrace_request from powerpc's compat_sys_ptrace. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 34 ++-------------------------------- 1 file changed, 2 insertions(+), 32 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index fea6206ff90f..6612304e11e3 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -112,20 +113,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, goto out_tsk; switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned int tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, (u32 __user *)data); - break; - } - /* * Read 4 bytes of the other process' storage * data is a pointer specifying where the user wants the @@ -225,19 +212,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; } - /* If I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: { - unsigned int tmp; - tmp = data; - ret = 0; - if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1) - == sizeof(tmp)) - break; - ret = -EIO; - break; - } - /* * Write 4 bytes into the other process' storage * data is the 4 bytes that the user wants written @@ -337,10 +311,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; } - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, (unsigned int __user *) data); - break; - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ int ui; if (!access_ok(VERIFY_WRITE, (void __user *)data, @@ -402,7 +372,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, break; default: - ret = ptrace_request(child, request, addr, data); + ret = compat_ptrace_request(child, request, addr, data); break; } out_tsk: -- cgit v1.2.2 From 81e695c026eeda9a97e412fa4f458e5cab2f6c85 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:58:55 -0800 Subject: [POWERPC] Use generic compat_sys_ptrace This replaces powerpc's compat_sys_ptrace with a compat_arch_ptrace and enables the new generic definition of compat_sys_ptrace instead. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 6612304e11e3..0f6eea086a23 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -85,33 +85,13 @@ static long compat_ptrace_old(struct task_struct *child, long request, return ret; } -long compat_sys_ptrace(int request, int pid, unsigned long addr, - unsigned long data) +long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + compat_ulong_t caddr, compat_ulong_t cdata) { - struct task_struct *child; + unsigned long addr = caddr; + unsigned long data = cdata; int ret; - lock_kernel(); - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out; - } - - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) - goto out_tsk; - switch (request) { /* * Read 4 bytes of the other process' storage @@ -375,9 +355,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr, ret = compat_ptrace_request(child, request, addr, data); break; } -out_tsk: - put_task_struct(child); -out: - unlock_kernel(); + return ret; } -- cgit v1.2.2 From 0deef2c7ab9dcf82f6ad26fc2fca358cd56c9cb9 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 20 Dec 2007 03:59:04 -0800 Subject: [POWERPC] Use regset code for compat PTRACE_*REGS* calls This cleans up the 32-bit ptrace syscall support to use user_regset calls to get at the register data for PTRACE_*REGS* calls. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace32.c | 96 +++++++++++------------------------------- 1 file changed, 25 insertions(+), 71 deletions(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 0f6eea086a23..4c1de6af4c09 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -46,43 +47,21 @@ static long compat_ptrace_old(struct task_struct *child, long request, long addr, long data) { - int ret = -EPERM; - - switch(request) { - case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = put_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; - } - - case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */ - int i; - unsigned long *reg = &((unsigned long *)child->thread.regs)[0]; - unsigned int __user *tmp = (unsigned int __user *)addr; - - CHECK_FULL_REGS(child->thread.regs); - for (i = 0; i < 32; i++) { - ret = get_user(*reg, tmp); - if (ret) - break; - reg++; - tmp++; - } - break; + switch (request) { + case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */ + return copy_regset_to_user(child, + task_user_regset_view(current), 0, + 0, 32 * sizeof(compat_long_t), + compat_ptr(data)); + + case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */ + return copy_regset_from_user(child, + task_user_regset_view(current), 0, + 0, 32 * sizeof(compat_long_t), + compat_ptr(data)); } - } - return ret; + return -EPERM; } long compat_arch_ptrace(struct task_struct *child, compat_long_t request, @@ -291,42 +270,17 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, break; } - case PTRACE_GETREGS: { /* Get all pt_regs from the child. */ - int ui; - if (!access_ok(VERIFY_WRITE, (void __user *)data, - PT_REGS_COUNT * sizeof(int))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret |= __put_user(ptrace_get_reg(child, ui), - (unsigned int __user *) data); - data += sizeof(int); - } - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - unsigned long tmp; - int ui; - if (!access_ok(VERIFY_READ, (void __user *)data, - PT_REGS_COUNT * sizeof(int))) { - ret = -EIO; - break; - } - CHECK_FULL_REGS(child->thread.regs); - ret = 0; - for (ui = 0; ui < PT_REGS_COUNT; ui ++) { - ret = __get_user(tmp, (unsigned int __user *) data); - if (ret) - break; - ptrace_put_reg(child, ui, tmp); - data += sizeof(int); - } - break; - } + case PTRACE_GETREGS: /* Get all pt_regs from the child. */ + return copy_regset_to_user( + child, task_user_regset_view(current), 0, + 0, PT_REGS_COUNT * sizeof(compat_long_t), + compat_ptr(data)); + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + return copy_regset_from_user( + child, task_user_regset_view(current), 0, + 0, PT_REGS_COUNT * sizeof(compat_long_t), + compat_ptr(data)); case PTRACE_GETFPREGS: case PTRACE_SETFPREGS: -- cgit v1.2.2 From 24f1a849614ba1805e26a05da7cc8c6bd67490ea Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 2 Jan 2008 17:05:48 -0800 Subject: [POWERPC] Add SPE registers to core dumps This makes the SPE register data appear in ELF core dumps, using the new n_type value NT_PPC_SPE (0x101). This new note type is not used by any consumers of core files yet, but support can be added. I don't even have any hardware with SPE capabilities, so I've never seen such a note. But this demonstrates how simple it is to export register information in core dumps when the user_regset style is used for the low-level code. Signed-off-by: Roland McGrath Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/powerpc') diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 7571c2e2d991..7673e9865733 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -581,7 +581,7 @@ static const struct user_regset compat_regsets[] = { #endif #ifdef CONFIG_SPE [REGSET_SPE] = { - .n = 35, + .core_note_type = NT_PPC_SPE, .n = 35, .size = sizeof(u32), .align = sizeof(u32), .active = evr_active, .get = evr_get, .set = evr_set }, -- cgit v1.2.2