* [PATCH 04/16] spufs: "stataus" isnt a word.
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/switch.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/switch.c
@@ -102,7 +102,7 @@ static inline int check_spu_isolate(stru
* saved at this time.
*/
isolate_state = SPU_STATUS_ISOLATED_STATE |
- SPU_STATUS_ISOLATED_LOAD_STAUTUS | SPU_STATUS_ISOLATED_EXIT_STAUTUS;
+ SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS;
return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
}
@@ -1046,12 +1046,12 @@ static inline int suspend_spe(struct spu
*/
if (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING) {
if (in_be32(&prob->spu_status_R) &
- SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+ SPU_STATUS_ISOLATED_EXIT_STATUS) {
POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) &
SPU_STATUS_RUNNING);
}
if ((in_be32(&prob->spu_status_R) &
- SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+ SPU_STATUS_ISOLATED_LOAD_STATUS)
|| (in_be32(&prob->spu_status_R) &
SPU_STATUS_ISOLATED_STATE)) {
out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
@@ -1085,7 +1085,7 @@ static inline void clear_spu_status(stru
*/
if (!(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)) {
if (in_be32(&prob->spu_status_R) &
- SPU_STATUS_ISOLATED_EXIT_STAUTUS) {
+ SPU_STATUS_ISOLATED_EXIT_STATUS) {
spu_mfc_sr1_set(spu,
MFC_STATE1_MASTER_RUN_CONTROL_MASK);
eieio();
@@ -1095,7 +1095,7 @@ static inline void clear_spu_status(stru
SPU_STATUS_RUNNING);
}
if ((in_be32(&prob->spu_status_R) &
- SPU_STATUS_ISOLATED_LOAD_STAUTUS)
+ SPU_STATUS_ISOLATED_LOAD_STATUS)
|| (in_be32(&prob->spu_status_R) &
SPU_STATUS_ISOLATED_STATE)) {
spu_mfc_sr1_set(spu,
Index: linux-2.6/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/spu.h
+++ linux-2.6/include/asm-powerpc/spu.h
@@ -291,8 +291,8 @@ struct spu_problem {
#define SPU_STATUS_INVALID_INSTR 0x20
#define SPU_STATUS_INVALID_CH 0x40
#define SPU_STATUS_ISOLATED_STATE 0x80
-#define SPU_STATUS_ISOLATED_LOAD_STAUTUS 0x200
-#define SPU_STATUS_ISOLATED_EXIT_STAUTUS 0x400
+#define SPU_STATUS_ISOLATED_LOAD_STATUS 0x200
+#define SPU_STATUS_ISOLATED_EXIT_STATUS 0x400
u8 pad_0x4028_0x402c[0x4]; /* 0x4028 */
u32 spu_spe_R; /* 0x402c */
u8 pad_0x4030_0x4034[0x4]; /* 0x4030 */
--
^ permalink raw reply
* [PATCH 05/16] spufs: allow isolated mode apps by starting the SPE loader
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
This patch adds general support for isolated mode SPE apps.
Isolated apps are started indirectly, by a dedicated loader "kernel".
This patch starts the loader when spe_create is invoked with the
ISOLATE flag. We do this at spe_create time to allow libspe to pass the
isolated app in before calling spe_run.
The loader is read from the device tree, at the location
"/spu-isolation/loader". If the loader is not present, an attempt to
start an isolated SPE binary will fail with -ENODEV.
Update: loader needs to be correctly aligned - copy to a kmalloced buf.
Update: remove workaround for systemsim/spurom 'L-bit' bug, which has
been fixed.
Update: don't write to runcntl on spu_run_init: SPU is already running.
Update: do spu_setup_isolated earlier
Tested on systemsim.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
arch/powerpc/platforms/cell/spu_base.c | 35 ++++++--
arch/powerpc/platforms/cell/spufs/inode.c | 117 ++++++++++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/run.c | 12 +--
3 files changed, 148 insertions(+), 16 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_base.c
@@ -89,7 +89,30 @@ static int __spu_trap_data_seg(struct sp
printk("%s: invalid access during switch!\n", __func__);
return 1;
}
- if (!mm || (REGION_ID(ea) != USER_REGION_ID)) {
+ esid = (ea & ESID_MASK) | SLB_ESID_V;
+
+ switch(REGION_ID(ea)) {
+ case USER_REGION_ID:
+#ifdef CONFIG_HUGETLB_PAGE
+ if (in_hugepage_area(mm->context, ea))
+ llp = mmu_psize_defs[mmu_huge_psize].sllp;
+ else
+#endif
+ llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
+ SLB_VSID_USER | llp;
+ break;
+ case VMALLOC_REGION_ID:
+ llp = mmu_psize_defs[mmu_virtual_psize].sllp;
+ vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
+ SLB_VSID_KERNEL | llp;
+ break;
+ case KERNEL_REGION_ID:
+ llp = mmu_psize_defs[mmu_linear_psize].sllp;
+ vsid = (get_kernel_vsid(ea) << SLB_VSID_SHIFT) |
+ SLB_VSID_KERNEL | llp;
+ break;
+ default:
/* Future: support kernel segments so that drivers
* can use SPUs.
*/
@@ -97,16 +120,6 @@ static int __spu_trap_data_seg(struct sp
return 1;
}
- esid = (ea & ESID_MASK) | SLB_ESID_V;
-#ifdef CONFIG_HUGETLB_PAGE
- if (in_hugepage_area(mm->context, ea))
- llp = mmu_psize_defs[mmu_huge_psize].sllp;
- else
-#endif
- llp = mmu_psize_defs[mmu_virtual_psize].sllp;
- vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
- SLB_VSID_USER | llp;
-
out_be64(&priv2->slb_index_W, spu->slb_replace);
out_be64(&priv2->slb_vsid_RW, vsid);
out_be64(&priv2->slb_esid_RW, esid);
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
@@ -33,6 +33,8 @@
#include <linux/slab.h>
#include <linux/parser.h>
+#include <asm/prom.h>
+#include <asm/spu_priv1.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/spu.h>
@@ -41,6 +43,7 @@
#include "spufs.h"
static kmem_cache_t *spufs_inode_cache;
+static char *isolated_loader;
static struct inode *
spufs_alloc_inode(struct super_block *sb)
@@ -232,6 +235,89 @@ struct file_operations spufs_context_fop
.fsync = simple_sync_file,
};
+static int spu_setup_isolated(struct spu_context *ctx)
+{
+ int ret;
+ u64 __iomem *mfc_cntl;
+ u64 sr1;
+ u32 status;
+ unsigned long timeout;
+ const u32 status_loading = SPU_STATUS_RUNNING
+ | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
+
+ if (!isolated_loader)
+ return -ENODEV;
+
+ if ((ret = spu_acquire_runnable(ctx)) != 0)
+ return ret;
+
+ mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
+
+ /* purge the MFC DMA queue to ensure no spurious accesses before we
+ * enter kernel mode */
+ timeout = jiffies + HZ;
+ out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST);
+ while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK)
+ != MFC_CNTL_PURGE_DMA_COMPLETE) {
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
+ __FUNCTION__);
+ ret = -EIO;
+ goto out_unlock;
+ }
+ cond_resched();
+ }
+
+ /* put the SPE in kernel mode to allow access to the loader */
+ sr1 = spu_mfc_sr1_get(ctx->spu);
+ sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK;
+ spu_mfc_sr1_set(ctx->spu, sr1);
+
+ /* start the loader */
+ ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32);
+ ctx->ops->signal2_write(ctx,
+ (unsigned long)isolated_loader & 0xffffffff);
+
+ ctx->ops->runcntl_write(ctx,
+ SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
+
+ ret = 0;
+ timeout = jiffies + HZ;
+ while (((status = ctx->ops->status_read(ctx)) & status_loading) ==
+ status_loading) {
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "%s: timeout waiting for loader\n",
+ __FUNCTION__);
+ ret = -EIO;
+ goto out_drop_priv;
+ }
+ cond_resched();
+ }
+
+ if (!(status & SPU_STATUS_RUNNING)) {
+ /* If isolated LOAD has failed: run SPU, we will get a stop-and
+ * signal later. */
+ pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
+ ret = -EACCES;
+
+ } else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+ /* This isn't allowed by the CBEA, but check anyway */
+ pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
+ ret = -EINVAL;
+ }
+
+out_drop_priv:
+ /* Finished accessing the loader. Drop kernel mode */
+ sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
+ spu_mfc_sr1_set(ctx->spu, sr1);
+
+out_unlock:
+ up_write(&ctx->state_sema);
+ return ret;
+}
+
static int
spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
int mode)
@@ -255,6 +341,11 @@ spufs_mkdir(struct inode *dir, struct de
goto out_iput;
ctx->flags = flags;
+ if (flags & SPU_CREATE_ISOLATE) {
+ ret = spu_setup_isolated(ctx);
+ if (ret)
+ goto out_iput;
+ }
inode->i_op = &spufs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
@@ -555,6 +646,30 @@ spufs_parse_options(char *options, struc
return 1;
}
+static void
+spufs_init_isolated_loader(void)
+{
+ struct device_node *dn;
+ const char *loader;
+ int size;
+
+ dn = of_find_node_by_path("/spu-isolation");
+ if (!dn)
+ return;
+
+ loader = get_property(dn, "loader", &size);
+ if (!loader)
+ return;
+
+ /* kmalloc should align on a 16 byte boundary..* */
+ isolated_loader = kmalloc(size, GFP_KERNEL);
+ if (!isolated_loader)
+ return;
+
+ memcpy(isolated_loader, loader, size);
+ printk(KERN_INFO "spufs: SPU isolation mode enabled\n");
+}
+
static int
spufs_create_root(struct super_block *sb, void *data)
{
@@ -640,6 +755,8 @@ static int __init spufs_init(void)
ret = register_spu_syscalls(&spufs_calls);
if (ret)
goto out_fs;
+
+ spufs_init_isolated_loader();
return 0;
out_fs:
unregister_filesystem(&spufs_type);
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/run.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/run.c
@@ -1,3 +1,5 @@
+#define DEBUG
+
#include <linux/wait.h>
#include <linux/ptrace.h>
@@ -56,12 +58,12 @@ static inline int spu_run_init(struct sp
if ((ret = spu_acquire_runnable(ctx)) != 0)
return ret;
- if (ctx->flags & SPU_CREATE_ISOLATE)
- runcntl |= SPU_RUNCNTL_ISOLATE;
- else
+ /* if we're in isolated mode, we would have started the SPU
+ * earlier, so don't do it again now. */
+ if (!(ctx->flags & SPU_CREATE_ISOLATE)) {
ctx->ops->npc_write(ctx, *npc);
-
- ctx->ops->runcntl_write(ctx, runcntl);
+ ctx->ops->runcntl_write(ctx, runcntl);
+ }
return 0;
}
--
^ permalink raw reply
* [PATCH 06/16] spufs: Add isolated-mode SPE recycling support
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Jeremy Kerr <jeremy@au1.ibm.com>
When in isolated mode, SPEs have access to an area of persistent
storage, which is per-SPE. In order for isolated-mode apps to
communicate arbitrary data through this storage, we need to ensure that
isolated physical SPEs can be reused for subsequent applications.
Add a file ("recycle") in a spethread dir to enable isolated-mode
recycling. By writing to this file, the kernel will reload the
isolated-mode loader kernel, allowing a new app to be run on the same
physical SPE.
This requires the spu_acquire_exclusive function to enforce exclusive
access to the SPE while the loader is initialised.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
Update: clarify locking, remove unnecessary yield, require >0 bytes
when writing to recycle file.
arch/powerpc/platforms/cell/spufs/context.c | 27 +++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/file.c | 32 ++++++++++++++++++++++++++++
arch/powerpc/platforms/cell/spufs/inode.c | 23 +++++++++++++-------
arch/powerpc/platforms/cell/spufs/spufs.h | 7 ++++++
4 files changed, 81 insertions(+), 8 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/context.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/context.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/context.c
@@ -120,6 +120,33 @@ void spu_unmap_mappings(struct spu_conte
unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
}
+int spu_acquire_exclusive(struct spu_context *ctx)
+{
+ int ret = 0;
+
+ down_write(&ctx->state_sema);
+ /* ctx is about to be freed, can't acquire any more */
+ if (!ctx->owner) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ctx->state == SPU_STATE_SAVED) {
+ ret = spu_activate(ctx, 0);
+ if (ret)
+ goto out;
+ ctx->state = SPU_STATE_RUNNABLE;
+ } else {
+ /* We need to exclude userspace access to the context. */
+ spu_unmap_mappings(ctx);
+ }
+
+out:
+ if (ret)
+ up_write(&ctx->state_sema);
+ return ret;
+}
+
int spu_acquire_runnable(struct spu_context *ctx)
{
int ret = 0;
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/file.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/file.c
@@ -1343,6 +1343,37 @@ static struct file_operations spufs_mfc_
.mmap = spufs_mfc_mmap,
};
+
+static int spufs_recycle_open(struct inode *inode, struct file *file)
+{
+ file->private_data = SPUFS_I(inode)->i_ctx;
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t spufs_recycle_write(struct file *file,
+ const char __user *buffer, size_t size, loff_t *pos)
+{
+ struct spu_context *ctx = file->private_data;
+ int ret;
+
+ if (!(ctx->flags & SPU_CREATE_ISOLATE))
+ return -EINVAL;
+
+ if (size < 1)
+ return -EINVAL;
+
+ ret = spu_recycle_isolated(ctx);
+
+ if (ret)
+ return ret;
+ return size;
+}
+
+static struct file_operations spufs_recycle_fops = {
+ .open = spufs_recycle_open,
+ .write = spufs_recycle_write,
+};
+
static void spufs_npc_set(void *data, u64 val)
{
struct spu_context *ctx = data;
@@ -1551,5 +1582,6 @@ struct tree_descr spufs_dir_nosched_cont
{ "psmap", &spufs_psmap_fops, 0666, },
{ "phys-id", &spufs_id_ops, 0666, },
{ "object-id", &spufs_object_id_ops, 0666, },
+ { "recycle", &spufs_recycle_fops, 0222, },
{},
};
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/inode.c
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/inode.c
@@ -248,7 +248,7 @@ static int spu_setup_isolated(struct spu
if (!isolated_loader)
return -ENODEV;
- if ((ret = spu_acquire_runnable(ctx)) != 0)
+ if ((ret = spu_acquire_exclusive(ctx)) != 0)
return ret;
mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
@@ -314,10 +314,16 @@ out_drop_priv:
spu_mfc_sr1_set(ctx->spu, sr1);
out_unlock:
- up_write(&ctx->state_sema);
+ spu_release_exclusive(ctx);
return ret;
}
+int spu_recycle_isolated(struct spu_context *ctx)
+{
+ ctx->ops->runcntl_stop(ctx);
+ return spu_setup_isolated(ctx);
+}
+
static int
spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
int mode)
@@ -341,12 +347,6 @@ spufs_mkdir(struct inode *dir, struct de
goto out_iput;
ctx->flags = flags;
- if (flags & SPU_CREATE_ISOLATE) {
- ret = spu_setup_isolated(ctx);
- if (ret)
- goto out_iput;
- }
-
inode->i_op = &spufs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
if (flags & SPU_CREATE_NOSCHED)
@@ -432,6 +432,13 @@ static int spufs_create_context(struct i
out_unlock:
mutex_unlock(&inode->i_mutex);
out:
+ if (ret >= 0 && (flags & SPU_CREATE_ISOLATE)) {
+ int setup_err = spu_setup_isolated(
+ SPUFS_I(dentry->d_inode)->i_ctx);
+ if (setup_err)
+ ret = setup_err;
+ }
+
dput(dentry);
return ret;
}
Index: linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spufs/spufs.h
+++ linux-2.6/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -163,6 +163,12 @@ void spu_acquire(struct spu_context *ctx
void spu_release(struct spu_context *ctx);
int spu_acquire_runnable(struct spu_context *ctx);
void spu_acquire_saved(struct spu_context *ctx);
+int spu_acquire_exclusive(struct spu_context *ctx);
+
+static inline void spu_release_exclusive(struct spu_context *ctx)
+{
+ up_write(&ctx->state_sema);
+}
int spu_activate(struct spu_context *ctx, u64 flags);
void spu_deactivate(struct spu_context *ctx);
@@ -170,6 +176,7 @@ void spu_yield(struct spu_context *ctx);
int __init spu_sched_init(void);
void __exit spu_sched_exit(void);
+int spu_recycle_isolated(struct spu_context *ctx);
/*
* spufs_wait
* Same as wait_event_interruptible(), except that here
--
^ permalink raw reply
* [PATCH 07/16] cell: update cell be register definitions
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Kevin Corry, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: David Erb <djerb@us.ibm.com>
There are a few definitions that are required by subsequent patches,
so add them here.
The original patch is from David Erb, but is significantly cleaned
up by Kevon Corry.
Cc: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -4,6 +4,11 @@
* This file is intended to hold the various register definitions for CBE
* on-chip system devices (memory controller, IO controller, etc...)
*
+ * (C) Copyright IBM Corporation 2001,2006
+ *
+ * Authors: Maximino Aguilar (maguilar@us.ibm.com)
+ * David J. Erb (djerb@us.ibm.com)
+ *
* (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
*/
@@ -22,6 +27,7 @@
#define HID0_CBE_THERM_INT_EN 0x0000000400000000ul
#define HID0_CBE_SYSERR_INT_EN 0x0000000200000000ul
+#define MAX_CBE 2
/*
*
@@ -29,45 +35,86 @@
*
*/
+union spe_reg {
+ u64 val;
+ u8 spe[8];
+};
+
+union ppe_spe_reg {
+ u64 val;
+ struct {
+ u32 ppe;
+ u32 spe;
+ };
+};
+
+
struct cbe_pmd_regs {
- u8 pad_0x0000_0x0800[0x0800 - 0x0000]; /* 0x0000 */
+ /* Debug Bus Control */
+ u64 pad_0x0000; /* 0x0000 */
+
+ u64 group_control; /* 0x0008 */
+
+ u8 pad_0x0010_0x00a8 [0x00a8 - 0x0010]; /* 0x0010 */
+
+ u64 debug_bus_control; /* 0x00a8 */
+
+ u8 pad_0x00b0_0x0100 [0x0100 - 0x00b0]; /* 0x00b0 */
+
+ u64 trace_aux_data; /* 0x0100 */
+ u64 trace_buffer_0_63; /* 0x0108 */
+ u64 trace_buffer_64_127; /* 0x0110 */
+ u64 trace_address; /* 0x0118 */
+ u64 ext_tr_timer; /* 0x0120 */
+
+ u8 pad_0x0128_0x0400 [0x0400 - 0x0128]; /* 0x0128 */
+
+ /* Performance Monitor */
+ u64 pm_status; /* 0x0400 */
+ u64 pm_control; /* 0x0408 */
+ u64 pm_interval; /* 0x0410 */
+ u64 pm_ctr[4]; /* 0x0418 */
+ u64 pm_start_stop; /* 0x0438 */
+ u64 pm07_control[8]; /* 0x0440 */
+
+ u8 pad_0x0480_0x0800 [0x0800 - 0x0480]; /* 0x0480 */
/* Thermal Sensor Registers */
- u64 ts_ctsr1; /* 0x0800 */
- u64 ts_ctsr2; /* 0x0808 */
- u64 ts_mtsr1; /* 0x0810 */
- u64 ts_mtsr2; /* 0x0818 */
- u64 ts_itr1; /* 0x0820 */
- u64 ts_itr2; /* 0x0828 */
- u64 ts_gitr; /* 0x0830 */
- u64 ts_isr; /* 0x0838 */
- u64 ts_imr; /* 0x0840 */
- u64 tm_cr1; /* 0x0848 */
- u64 tm_cr2; /* 0x0850 */
- u64 tm_simr; /* 0x0858 */
- u64 tm_tpr; /* 0x0860 */
- u64 tm_str1; /* 0x0868 */
- u64 tm_str2; /* 0x0870 */
- u64 tm_tsr; /* 0x0878 */
+ union spe_reg ts_ctsr1; /* 0x0800 */
+ u64 ts_ctsr2; /* 0x0808 */
+ union spe_reg ts_mtsr1; /* 0x0810 */
+ u64 ts_mtsr2; /* 0x0818 */
+ union spe_reg ts_itr1; /* 0x0820 */
+ u64 ts_itr2; /* 0x0828 */
+ u64 ts_gitr; /* 0x0830 */
+ u64 ts_isr; /* 0x0838 */
+ u64 ts_imr; /* 0x0840 */
+ union spe_reg tm_cr1; /* 0x0848 */
+ u64 tm_cr2; /* 0x0850 */
+ u64 tm_simr; /* 0x0858 */
+ union ppe_spe_reg tm_tpr; /* 0x0860 */
+ union spe_reg tm_str1; /* 0x0868 */
+ u64 tm_str2; /* 0x0870 */
+ union ppe_spe_reg tm_tsr; /* 0x0878 */
/* Power Management */
- u64 pm_control; /* 0x0880 */
-#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000
- u64 pm_status; /* 0x0888 */
+ u64 pmcr; /* 0x0880 */
+#define CBE_PMD_PAUSE_ZERO_CONTROL 0x10000
+ u64 pmsr; /* 0x0888 */
/* Time Base Register */
- u64 tbr; /* 0x0890 */
+ u64 tbr; /* 0x0890 */
- u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */
+ u8 pad_0x0898_0x0c00 [0x0c00 - 0x0898]; /* 0x0898 */
/* Fault Isolation Registers */
- u64 checkstop_fir; /* 0x0c00 */
- u64 recoverable_fir;
- u64 spec_att_mchk_fir;
- u64 fir_mode_reg;
- u64 fir_enable_mask;
+ u64 checkstop_fir; /* 0x0c00 */
+ u64 recoverable_fir; /* 0x0c08 */
+ u64 spec_att_mchk_fir; /* 0x0c10 */
+ u64 fir_mode_reg; /* 0x0c18 */
+ u64 fir_enable_mask; /* 0x0c20 */
- u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */
+ u8 pad_0x0c28_0x1000 [0x1000 - 0x0c28]; /* 0x0c28 */
};
extern struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np);
@@ -102,18 +149,20 @@ struct cbe_iic_regs {
/* IIC interrupt registers */
struct cbe_iic_thread_regs thread[2]; /* 0x0400 */
- u64 iic_ir; /* 0x0440 */
- u64 iic_is; /* 0x0448 */
+
+ u64 iic_ir; /* 0x0440 */
+ u64 iic_is; /* 0x0448 */
+#define CBE_IIC_IS_PMI 0x2
u8 pad_0x0450_0x0500[0x0500 - 0x0450]; /* 0x0450 */
/* IOC FIR */
u64 ioc_fir_reset; /* 0x0500 */
- u64 ioc_fir_set;
- u64 ioc_checkstop_enable;
- u64 ioc_fir_error_mask;
- u64 ioc_syserr_enable;
- u64 ioc_fir;
+ u64 ioc_fir_set; /* 0x0508 */
+ u64 ioc_checkstop_enable; /* 0x0510 */
+ u64 ioc_fir_error_mask; /* 0x0518 */
+ u64 ioc_syserr_enable; /* 0x0520 */
+ u64 ioc_fir; /* 0x0528 */
u8 pad_0x0530_0x1000[0x1000 - 0x0530]; /* 0x0530 */
};
@@ -122,6 +171,48 @@ extern struct cbe_iic_regs __iomem *cbe_
extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
+struct cbe_mic_tm_regs {
+ u8 pad_0x0000_0x0040[0x0040 - 0x0000]; /* 0x0000 */
+
+ u64 mic_ctl_cnfg2; /* 0x0040 */
+#define CBE_MIC_ENABLE_AUX_TRC 0x8000000000000000LL
+#define CBE_MIC_DISABLE_PWR_SAV_2 0x0200000000000000LL
+#define CBE_MIC_DISABLE_AUX_TRC_WRAP 0x0100000000000000LL
+#define CBE_MIC_ENABLE_AUX_TRC_INT 0x0080000000000000LL
+
+ u64 pad_0x0048; /* 0x0048 */
+
+ u64 mic_aux_trc_base; /* 0x0050 */
+ u64 mic_aux_trc_max_addr; /* 0x0058 */
+ u64 mic_aux_trc_cur_addr; /* 0x0060 */
+ u64 mic_aux_trc_grf_addr; /* 0x0068 */
+ u64 mic_aux_trc_grf_data; /* 0x0070 */
+
+ u64 pad_0x0078; /* 0x0078 */
+
+ u64 mic_ctl_cnfg_0; /* 0x0080 */
+#define CBE_MIC_DISABLE_PWR_SAV_0 0x8000000000000000LL
+
+ u64 pad_0x0088; /* 0x0088 */
+
+ u64 slow_fast_timer_0; /* 0x0090 */
+ u64 slow_next_timer_0; /* 0x0098 */
+
+ u8 pad_0x00a0_0x01c0[0x01c0 - 0x0a0]; /* 0x00a0 */
+
+ u64 mic_ctl_cnfg_1; /* 0x01c0 */
+#define CBE_MIC_DISABLE_PWR_SAV_1 0x8000000000000000LL
+ u64 pad_0x01c8; /* 0x01c8 */
+
+ u64 slow_fast_timer_1; /* 0x01d0 */
+ u64 slow_next_timer_1; /* 0x01d8 */
+
+ u8 pad_0x01e0_0x1000[0x1000 - 0x01e0]; /* 0x01e0 */
+};
+
+extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
+extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
+
/* Init this module early */
extern void cbe_regs_init(void);
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.c
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
@@ -8,6 +8,7 @@
#include <linux/percpu.h>
#include <linux/types.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -16,8 +17,6 @@
#include "cbe_regs.h"
-#define MAX_CBE 2
-
/*
* Current implementation uses "cpu" nodes. We build our own mapping
* array of cpu numbers to cpu nodes locally for now to allow interrupt
@@ -30,6 +29,7 @@ static struct cbe_regs_map
struct device_node *cpu_node;
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_iic_regs __iomem *iic_regs;
+ struct cbe_mic_tm_regs __iomem *mic_tm_regs;
} cbe_regs_maps[MAX_CBE];
static int cbe_regs_map_count;
@@ -42,6 +42,19 @@ static struct cbe_thread_map
static struct cbe_regs_map *cbe_find_map(struct device_node *np)
{
int i;
+ struct device_node *tmp_np;
+
+ if (strcasecmp(np->type, "spe") == 0) {
+ if (np->data == NULL) {
+ /* walk up path until cpu node was found */
+ tmp_np = np->parent;
+ while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
+ tmp_np = tmp_np->parent;
+
+ np->data = cbe_find_map(tmp_np);
+ }
+ return np->data;
+ }
for (i = 0; i < cbe_regs_map_count; i++)
if (cbe_regs_maps[i].cpu_node == np)
@@ -56,6 +69,7 @@ struct cbe_pmd_regs __iomem *cbe_get_pmd
return NULL;
return map->pmd_regs;
}
+EXPORT_SYMBOL_GPL(cbe_get_pmd_regs);
struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu)
{
@@ -64,7 +78,7 @@ struct cbe_pmd_regs __iomem *cbe_get_cpu
return NULL;
return map->pmd_regs;
}
-
+EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
{
@@ -73,6 +87,7 @@ struct cbe_iic_regs __iomem *cbe_get_iic
return NULL;
return map->iic_regs;
}
+
struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu)
{
struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
@@ -81,6 +96,24 @@ struct cbe_iic_regs __iomem *cbe_get_cpu
return map->iic_regs;
}
+struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np)
+{
+ struct cbe_regs_map *map = cbe_find_map(np);
+ if (map == NULL)
+ return NULL;
+ return map->mic_tm_regs;
+}
+
+struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
+{
+ struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+ if (map == NULL)
+ return NULL;
+ return map->mic_tm_regs;
+}
+EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
+
+
void __init cbe_regs_init(void)
{
int i;
@@ -119,6 +152,11 @@ void __init cbe_regs_init(void)
prop = get_property(cpu, "iic", NULL);
if (prop != NULL)
map->iic_regs = ioremap(prop->address, prop->len);
+
+ prop = (struct address_prop *)get_property(cpu, "mic-tm",
+ NULL);
+ if (prop != NULL)
+ map->mic_tm_regs = ioremap(prop->address, prop->len);
}
}
Index: linux-2.6/arch/powerpc/platforms/cell/pervasive.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pervasive.c
+++ linux-2.6/arch/powerpc/platforms/cell/pervasive.c
@@ -54,9 +54,9 @@ static void __init cbe_enable_pause_zero
pr_debug("Power Management: CPU %d\n", smp_processor_id());
/* Enable Pause(0) control bit */
- temp_register = in_be64(&pregs->pm_control);
+ temp_register = in_be64(&pregs->pmcr);
- out_be64(&pregs->pm_control,
+ out_be64(&pregs->pmcr,
temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
/* Enable DEC and EE interrupt request */
@@ -87,7 +87,7 @@ static void cbe_idle(void)
unsigned long ctrl;
/* Why do we do that on every idle ? Couldn't that be done once for
- * all or do we lose the state some way ? Also, the pm_control
+ * all or do we lose the state some way ? Also, the pmcr
* register setting, that can't be set once at boot ? We really want
* to move that away in order to implement a simple powersave
*/
--
^ permalink raw reply
* [PATCH 08/16] cell: add shadow registers for pmd_reg
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Kevin Corry, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Kevin Corry <kevcorry@us.ibm.com>
Many of the registers in the performance monitoring unit are write-only.
We need to save a "shadow" copy when we write to those registers so we
can retrieve the values if we need them later.
The new cbe_pmd_shadow_regs structure is added to the cbe_regs_map structure
so we have the appropriate per-node copies of these shadow values.
Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.c
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.c
@@ -30,6 +30,7 @@ static struct cbe_regs_map
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_iic_regs __iomem *iic_regs;
struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+ struct cbe_pmd_shadow_regs pmd_shadow_regs;
} cbe_regs_maps[MAX_CBE];
static int cbe_regs_map_count;
@@ -80,6 +81,22 @@ struct cbe_pmd_regs __iomem *cbe_get_cpu
}
EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs);
+struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np)
+{
+ struct cbe_regs_map *map = cbe_find_map(np);
+ if (map == NULL)
+ return NULL;
+ return &map->pmd_shadow_regs;
+}
+
+struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu)
+{
+ struct cbe_regs_map *map = cbe_thread_map[cpu].regs;
+ if (map == NULL)
+ return NULL;
+ return &map->pmd_shadow_regs;
+}
+
struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np)
{
struct cbe_regs_map *map = cbe_find_map(np);
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -121,6 +121,41 @@ extern struct cbe_pmd_regs __iomem *cbe_
extern struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu);
/*
+ * PMU shadow registers
+ *
+ * Many of the registers in the performance monitoring unit are write-only,
+ * so we need to save a copy of what we write to those registers.
+ *
+ * The actual data counters are read/write. However, writing to the counters
+ * only takes effect if the PMU is enabled. Otherwise the value is stored in
+ * a hardware latch until the next time the PMU is enabled. So we save a copy
+ * of the counter values if we need to read them back while the PMU is
+ * disabled. The counter_value_in_latch field is a bitmap indicating which
+ * counters currently have a value waiting to be written.
+ */
+
+#define NR_PHYS_CTRS 4
+#define NR_CTRS (NR_PHYS_CTRS * 2)
+
+struct cbe_pmd_shadow_regs {
+ u32 group_control;
+ u32 debug_bus_control;
+ u32 trace_address;
+ u32 ext_tr_timer;
+ u32 pm_status;
+ u32 pm_control;
+ u32 pm_interval;
+ u32 pm_start_stop;
+ u32 pm07_control[NR_CTRS];
+
+ u32 pm_ctr[NR_PHYS_CTRS];
+ u32 counter_value_in_latch;
+};
+
+extern struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np);
+extern struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu);
+
+/*
*
* IIC unit register definitions
*
--
^ permalink raw reply
* [PATCH 09/16] cell: add low-level performance monitoring code
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Kevin Corry, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Kevin Corry <kevcorry@us.ibm.com>
Add routines for accessing the registers and counters in the performance
monitoring unit.
Signed-off-by: Kevin Corry <kevcorry@us.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
- cbe_regs.o spider-pic.o pervasive.o
+ cbe_regs.o spider-pic.o pervasive.o \
+ pmu.o
obj-$(CONFIG_CBE_RAS) += ras.o
ifeq ($(CONFIG_SMP),y)
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/cbe_regs.h
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_regs.h
@@ -35,6 +35,11 @@
*
*/
+/* Macros for the pm_control register. */
+#define CBE_PM_16BIT_CTR(ctr) (1 << (24 - ((ctr) & (NR_PHYS_CTRS - 1))))
+#define CBE_PM_ENABLE_PERF_MON 0x80000000
+
+
union spe_reg {
u64 val;
u8 spe[8];
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.c
@@ -0,0 +1,328 @@
+/*
+ * Cell Broadband Engine Performance Monitor
+ *
+ * (C) Copyright IBM Corporation 2001,2006
+ *
+ * Author:
+ * David Erb (djerb@us.ibm.com)
+ * Kevin Corry (kevcorry@us.ibm.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/reg.h>
+#include <asm/spu.h>
+
+#include "cbe_regs.h"
+#include "interrupt.h"
+#include "pmu.h"
+
+/*
+ * When writing to write-only mmio addresses, save a shadow copy. All of the
+ * registers are 32-bit, but stored in the upper-half of a 64-bit field in
+ * pmd_regs.
+ */
+
+#define WRITE_WO_MMIO(reg, x) \
+ do { \
+ u32 _x = (x); \
+ struct cbe_pmd_regs __iomem *pmd_regs; \
+ struct cbe_pmd_shadow_regs *shadow_regs; \
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
+ shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
+ out_be64(&(pmd_regs->reg), (((u64)_x) << 32)); \
+ shadow_regs->reg = _x; \
+ } while (0)
+
+#define READ_SHADOW_REG(val, reg) \
+ do { \
+ struct cbe_pmd_shadow_regs *shadow_regs; \
+ shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
+ (val) = shadow_regs->reg; \
+ } while (0)
+
+#define READ_MMIO_UPPER32(val, reg) \
+ do { \
+ struct cbe_pmd_regs __iomem *pmd_regs; \
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu); \
+ (val) = (u32)(in_be64(&pmd_regs->reg) >> 32); \
+ } while (0)
+
+/*
+ * Physical counter registers.
+ * Each physical counter can act as one 32-bit counter or two 16-bit counters.
+ */
+
+u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
+{
+ u32 val_in_latch, val = 0;
+
+ if (phys_ctr < NR_PHYS_CTRS) {
+ READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
+
+ /* Read the latch or the actual counter, whichever is newer. */
+ if (val_in_latch & (1 << phys_ctr)) {
+ READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
+ } else {
+ READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
+ }
+ }
+
+ return val;
+}
+
+void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
+{
+ struct cbe_pmd_shadow_regs *shadow_regs;
+ u32 pm_ctrl;
+
+ if (phys_ctr < NR_PHYS_CTRS) {
+ /* Writing to a counter only writes to a hardware latch.
+ * The new value is not propagated to the actual counter
+ * until the performance monitor is enabled.
+ */
+ WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
+
+ pm_ctrl = cbe_read_pm(cpu, pm_control);
+ if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
+ /* The counters are already active, so we need to
+ * rewrite the pm_control register to "re-enable"
+ * the PMU.
+ */
+ cbe_write_pm(cpu, pm_control, pm_ctrl);
+ } else {
+ shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
+ shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
+ }
+ }
+}
+
+/*
+ * "Logical" counter registers.
+ * These will read/write 16-bits or 32-bits depending on the
+ * current size of the counter. Counters 4 - 7 are always 16-bit.
+ */
+
+u32 cbe_read_ctr(u32 cpu, u32 ctr)
+{
+ u32 val;
+ u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+ val = cbe_read_phys_ctr(cpu, phys_ctr);
+
+ if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
+ val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
+
+ return val;
+}
+
+void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
+{
+ u32 phys_ctr;
+ u32 phys_val;
+
+ phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+ if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
+ phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
+
+ if (ctr < NR_PHYS_CTRS)
+ val = (val << 16) | (phys_val & 0xffff);
+ else
+ val = (val & 0xffff) | (phys_val & 0xffff0000);
+ }
+
+ cbe_write_phys_ctr(cpu, phys_ctr, val);
+}
+
+/*
+ * Counter-control registers.
+ * Each "logical" counter has a corresponding control register.
+ */
+
+u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
+{
+ u32 pm07_control = 0;
+
+ if (ctr < NR_CTRS)
+ READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
+
+ return pm07_control;
+}
+
+void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
+{
+ if (ctr < NR_CTRS)
+ WRITE_WO_MMIO(pm07_control[ctr], val);
+}
+
+/*
+ * Other PMU control registers. Most of these are write-only.
+ */
+
+u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
+{
+ u32 val = 0;
+
+ switch (reg) {
+ case group_control:
+ READ_SHADOW_REG(val, group_control);
+ break;
+
+ case debug_bus_control:
+ READ_SHADOW_REG(val, debug_bus_control);
+ break;
+
+ case trace_address:
+ READ_MMIO_UPPER32(val, trace_address);
+ break;
+
+ case ext_tr_timer:
+ READ_SHADOW_REG(val, ext_tr_timer);
+ break;
+
+ case pm_status:
+ READ_MMIO_UPPER32(val, pm_status);
+ break;
+
+ case pm_control:
+ READ_SHADOW_REG(val, pm_control);
+ break;
+
+ case pm_interval:
+ READ_SHADOW_REG(val, pm_interval);
+ break;
+
+ case pm_start_stop:
+ READ_SHADOW_REG(val, pm_start_stop);
+ break;
+ }
+
+ return val;
+}
+
+void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
+{
+ switch (reg) {
+ case group_control:
+ WRITE_WO_MMIO(group_control, val);
+ break;
+
+ case debug_bus_control:
+ WRITE_WO_MMIO(debug_bus_control, val);
+ break;
+
+ case trace_address:
+ WRITE_WO_MMIO(trace_address, val);
+ break;
+
+ case ext_tr_timer:
+ WRITE_WO_MMIO(ext_tr_timer, val);
+ break;
+
+ case pm_status:
+ WRITE_WO_MMIO(pm_status, val);
+ break;
+
+ case pm_control:
+ WRITE_WO_MMIO(pm_control, val);
+ break;
+
+ case pm_interval:
+ WRITE_WO_MMIO(pm_interval, val);
+ break;
+
+ case pm_start_stop:
+ WRITE_WO_MMIO(pm_start_stop, val);
+ break;
+ }
+}
+
+/*
+ * Get/set the size of a physical counter to either 16 or 32 bits.
+ */
+
+u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
+{
+ u32 pm_ctrl, size = 0;
+
+ if (phys_ctr < NR_PHYS_CTRS) {
+ pm_ctrl = cbe_read_pm(cpu, pm_control);
+ size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
+ }
+
+ return size;
+}
+
+void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
+{
+ u32 pm_ctrl;
+
+ if (phys_ctr < NR_PHYS_CTRS) {
+ pm_ctrl = cbe_read_pm(cpu, pm_control);
+ switch (ctr_size) {
+ case 16:
+ pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
+ break;
+
+ case 32:
+ pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
+ break;
+ }
+ cbe_write_pm(cpu, pm_control, pm_ctrl);
+ }
+}
+
+/*
+ * Enable/disable the entire performance monitoring unit.
+ * When we enable the PMU, all pending writes to counters get committed.
+ */
+
+void cbe_enable_pm(u32 cpu)
+{
+ struct cbe_pmd_shadow_regs *shadow_regs;
+ u32 pm_ctrl;
+
+ shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
+ shadow_regs->counter_value_in_latch = 0;
+
+ pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
+ cbe_write_pm(cpu, pm_control, pm_ctrl);
+}
+
+void cbe_disable_pm(u32 cpu)
+{
+ u32 pm_ctrl;
+ pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
+ cbe_write_pm(cpu, pm_control, pm_ctrl);
+}
+
+/*
+ * Reading from the trace_buffer.
+ * The trace buffer is two 64-bit registers. Reading from
+ * the second half automatically increments the trace_address.
+ */
+
+void cbe_read_trace_buffer(u32 cpu, u64 *buf)
+{
+ struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+ *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
+ *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
+}
+
Index: linux-2.6/arch/powerpc/platforms/cell/pmu.h
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/pmu.h
@@ -0,0 +1,57 @@
+/*
+ * Cell Broadband Engine Performance Monitor
+ *
+ * (C) Copyright IBM Corporation 2001,2006
+ *
+ * Author:
+ * David Erb (djerb@us.ibm.com)
+ * Kevin Corry (kevcorry@us.ibm.com)
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PERFMON_H__
+#define __PERFMON_H__
+
+enum pm_reg_name {
+ group_control,
+ debug_bus_control,
+ trace_address,
+ ext_tr_timer,
+ pm_status,
+ pm_control,
+ pm_interval,
+ pm_start_stop,
+};
+
+extern u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr);
+extern void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
+extern u32 cbe_read_ctr(u32 cpu, u32 ctr);
+extern void cbe_write_ctr(u32 cpu, u32 ctr, u32 val);
+
+extern u32 cbe_read_pm07_control(u32 cpu, u32 ctr);
+extern void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val);
+extern u32 cbe_read_pm (u32 cpu, enum pm_reg_name reg);
+extern void cbe_write_pm (u32 cpu, enum pm_reg_name reg, u32 val);
+
+extern u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr);
+extern void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
+
+extern void cbe_enable_pm(u32 cpu);
+extern void cbe_disable_pm(u32 cpu);
+
+extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
+
+#endif
--
^ permalink raw reply
* [PATCH 10/16] cell: add support for registering sysfs attributes to spus
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Christian Krafft, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Christian Krafft <krafft@de.ibm.com>
In order to add sysfs attributes to all spu's, there is a
need for a list of all available spu's. Adding the device_node
makes also sense, as it is needed for proper register access.
This patch also adds two functions to create and remove sysfs
attributes and attribute_groups to all spus.
That allows to group spu attributes in a subdirectory like:
/sys/devices/system/spu/spuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.
Signed-off-by: Christian Krafft <krafft@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/include/asm-powerpc/spu.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/spu.h
+++ linux-2.6/include/asm-powerpc/spu.h
@@ -115,6 +115,7 @@ struct spu {
struct spu_priv2 __iomem *priv2;
struct list_head list;
struct list_head sched_list;
+ struct list_head full_list;
int number;
int nid;
unsigned int irqs[3];
@@ -143,6 +144,8 @@ struct spu {
char irq_c1[8];
char irq_c2[8];
+ struct device_node *devnode;
+
struct sys_device sysdev;
};
@@ -200,6 +203,12 @@ static inline void unregister_spu_syscal
}
#endif /* MODULE */
+int spu_add_sysdev_attr(struct sysdev_attribute *attr);
+void spu_remove_sysdev_attr(struct sysdev_attribute *attr);
+
+int spu_add_sysdev_attr_group(struct attribute_group *attrs);
+void spu_remove_sysdev_attr_group(struct attribute_group *attrs);
+
/*
* Notifier blocks:
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_base.c
@@ -333,6 +333,7 @@ static void spu_free_irqs(struct spu *sp
}
static struct list_head spu_list[MAX_NUMNODES];
+static LIST_HEAD(spu_full_list);
static DEFINE_MUTEX(spu_mutex);
static void spu_init_channels(struct spu *spu)
@@ -744,6 +745,57 @@ struct sysdev_class spu_sysdev_class = {
set_kset_name("spu")
};
+int spu_add_sysdev_attr(struct sysdev_attribute *attr)
+{
+ struct spu *spu;
+ mutex_lock(&spu_mutex);
+
+ list_for_each_entry(spu, &spu_full_list, full_list)
+ sysdev_create_file(&spu->sysdev, attr);
+
+ mutex_unlock(&spu_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
+
+int spu_add_sysdev_attr_group(struct attribute_group *attrs)
+{
+ struct spu *spu;
+ mutex_lock(&spu_mutex);
+
+ list_for_each_entry(spu, &spu_full_list, full_list)
+ sysfs_create_group(&spu->sysdev.kobj, attrs);
+
+ mutex_unlock(&spu_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
+
+
+void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
+{
+ struct spu *spu;
+ mutex_lock(&spu_mutex);
+
+ list_for_each_entry(spu, &spu_full_list, full_list)
+ sysdev_remove_file(&spu->sysdev, attr);
+
+ mutex_unlock(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
+
+void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
+{
+ struct spu *spu;
+ mutex_lock(&spu_mutex);
+
+ list_for_each_entry(spu, &spu_full_list, full_list)
+ sysfs_remove_group(&spu->sysdev.kobj, attrs);
+
+ mutex_unlock(&spu_mutex);
+}
+EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
+
static int spu_create_sysdev(struct spu *spu)
{
int ret;
@@ -817,6 +869,9 @@ static int __init create_spu(struct devi
goto out_free_irqs;
list_add(&spu->list, &spu_list[spu->node]);
+ list_add(&spu->full_list, &spu_full_list);
+ spu->devnode = of_node_get(spe);
+
mutex_unlock(&spu_mutex);
pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n",
@@ -839,6 +894,9 @@ out:
static void destroy_spu(struct spu *spu)
{
list_del_init(&spu->list);
+ list_del_init(&spu->full_list);
+
+ of_node_put(spu->devnode);
spu_destroy_sysdev(spu);
spu_free_irqs(spu);
--
^ permalink raw reply
* [PATCH 11/16] sysfs: add support for adding/removing spu sysfs attributes
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Christian Krafft <krafft@de.ibm.com>
This patch adds two functions to create and remove sysfs attributes and
attribute_group to all cpus. That allows to register sysfs attributes in
a subdirectory like: /sys/devices/system/cpu/cpuX/group_name/what_ever
This will be used by cbe_thermal to group all attributes dealing with
thermal support in one directory.
Signed-of-by: Christian Krafft <krafft@de.ibm.com>
Index: linux-2.6/arch/powerpc/kernel/sysfs.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/sysfs.c
+++ linux-2.6/arch/powerpc/kernel/sysfs.c
@@ -299,6 +299,72 @@ static struct notifier_block __cpuinitda
.notifier_call = sysfs_cpu_notify,
};
+static DEFINE_MUTEX(cpu_mutex);
+
+int cpu_add_sysdev_attr(struct sysdev_attribute *attr)
+{
+ int cpu;
+
+ mutex_lock(&cpu_mutex);
+
+ for_each_possible_cpu(cpu) {
+ sysdev_create_file(get_cpu_sysdev(cpu), attr);
+ }
+
+ mutex_unlock(&cpu_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr);
+
+int cpu_add_sysdev_attr_group(struct attribute_group *attrs)
+{
+ int cpu;
+ struct sys_device *sysdev;
+
+ mutex_lock(&cpu_mutex);
+
+ for_each_possible_cpu(cpu) {
+ sysdev = get_cpu_sysdev(cpu);
+ sysfs_create_group(&sysdev->kobj, attrs);
+ }
+
+ mutex_unlock(&cpu_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpu_add_sysdev_attr_group);
+
+
+void cpu_remove_sysdev_attr(struct sysdev_attribute *attr)
+{
+ int cpu;
+
+ mutex_lock(&cpu_mutex);
+
+ for_each_possible_cpu(cpu) {
+ sysdev_remove_file(get_cpu_sysdev(cpu), attr);
+ }
+
+ mutex_unlock(&cpu_mutex);
+}
+EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr);
+
+void cpu_remove_sysdev_attr_group(struct attribute_group *attrs)
+{
+ int cpu;
+ struct sys_device *sysdev;
+
+ mutex_lock(&cpu_mutex);
+
+ for_each_possible_cpu(cpu) {
+ sysdev = get_cpu_sysdev(cpu);
+ sysfs_remove_group(&sysdev->kobj, attrs);
+ }
+
+ mutex_unlock(&cpu_mutex);
+}
+EXPORT_SYMBOL_GPL(cpu_remove_sysdev_attr_group);
+
+
/* NUMA stuff */
#ifdef CONFIG_NUMA
Index: linux-2.6/include/linux/cpu.h
===================================================================
--- linux-2.6.orig/include/linux/cpu.h
+++ linux-2.6/include/linux/cpu.h
@@ -33,6 +33,14 @@ struct cpu {
extern int register_cpu(struct cpu *cpu, int num);
extern struct sys_device *get_cpu_sysdev(unsigned cpu);
+
+extern int cpu_add_sysdev_attr(struct sysdev_attribute *attr);
+extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr);
+
+extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs);
+extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs);
+
+
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *cpu);
#endif
--
^ permalink raw reply
* [PATCH 12/16] cell: add temperature to SPU and CPU sysfs entries
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Christian Krafft, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Christian Krafft <krafft@de.ibm.com>
This patch adds a module that registers sysfs attributes to CPU and SPU
containing the temperature of the CBE.
They can be found under
/sys/devices/system/spu/cpuX/thermal/temperature[0|1]
/sys/devices/system/spu/spuX/thermal/temperature
The temperature is read from the on-chip temperature sensors.
Signed-off-by: Christian Krafft <krafft@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-2.6/arch/powerpc/platforms/cell/Kconfig
@@ -20,4 +20,9 @@ config CBE_RAS
bool "RAS features for bare metal Cell BE"
default y
+config CBE_THERM
+ tristate "CBE thermal support"
+ default m
+ depends on CBE_RAS
+
endmenu
Index: linux-2.6/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/Makefile
@@ -3,6 +3,8 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += interr
pmu.o
obj-$(CONFIG_CBE_RAS) += ras.o
+obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
+
ifeq ($(CONFIG_SMP),y)
obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
endif
Index: linux-2.6/arch/powerpc/configs/cell_defconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/configs/cell_defconfig
+++ linux-2.6/arch/powerpc/configs/cell_defconfig
@@ -149,6 +149,7 @@ CONFIG_MMIO_NVRAM=y
CONFIG_SPU_FS=m
CONFIG_SPU_BASE=y
CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
#
# Kernel options
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_thermal.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -0,0 +1,225 @@
+/*
+ * thermal support for the cell processor
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <asm/spu.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#include "cbe_regs.h"
+
+static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
+{
+ struct spu *spu;
+
+ spu = container_of(sysdev, struct spu, sysdev);
+
+ return cbe_get_pmd_regs(spu->devnode);
+}
+
+/* returns the value for a given spu in a given register */
+static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
+{
+ unsigned int *id;
+ union spe_reg value;
+ struct spu *spu;
+
+ /* getting the id from the reg attribute will not work on future device-tree layouts
+ * in future we should store the id to the spu struct and use it here */
+ spu = container_of(sysdev, struct spu, sysdev);
+ id = (unsigned int *)get_property(spu->devnode, "reg", NULL);
+ value.val = in_be64(®->val);
+
+ return value.spe[*id];
+}
+
+static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
+{
+ int value;
+ struct cbe_pmd_regs __iomem *pmd_regs;
+
+ pmd_regs = get_pmd_regs(sysdev);
+
+ value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
+ /* clear all other bits */
+ value &= 0x3F;
+ /* temp is stored in steps of 2 degrees */
+ value *= 2;
+ /* base temp is 65 degrees */
+ value += 65;
+
+ return sprintf(buf, "%d\n", (int) value);
+}
+
+static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
+{
+ struct cbe_pmd_regs __iomem *pmd_regs;
+ u64 value;
+
+ pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
+ value = in_be64(&pmd_regs->ts_ctsr2);
+
+ /* access the corresponding byte */
+ value >>= pos;
+ /* clear all other bits */
+ value &= 0x3F;
+ /* temp is stored in steps of 2 degrees */
+ value *= 2;
+ /* base temp is 65 degrees */
+ value += 65;
+
+ return sprintf(buf, "%d\n", (int) value);
+}
+
+
+/* shows the temperature of the DTS on the PPE,
+ * located near the linear thermal sensor */
+static ssize_t ppe_show_temp0(struct sys_device *sysdev, char *buf)
+{
+ return ppe_show_temp(sysdev, buf, 32);
+}
+
+/* shows the temperature of the second DTS on the PPE */
+static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
+{
+ return ppe_show_temp(sysdev, buf, 0);
+}
+
+static struct sysdev_attribute attr_spu_temperature = {
+ .attr = {.name = "temperature", .mode = 0400 },
+ .show = spu_show_temp,
+};
+
+static struct attribute *spu_attributes[] = {
+ &attr_spu_temperature.attr,
+};
+
+static struct attribute_group spu_attribute_group = {
+ .name = "thermal",
+ .attrs = spu_attributes,
+};
+
+static struct sysdev_attribute attr_ppe_temperature0 = {
+ .attr = {.name = "temperature0", .mode = 0400 },
+ .show = ppe_show_temp0,
+};
+
+static struct sysdev_attribute attr_ppe_temperature1 = {
+ .attr = {.name = "temperature1", .mode = 0400 },
+ .show = ppe_show_temp1,
+};
+
+static struct attribute *ppe_attributes[] = {
+ &attr_ppe_temperature0.attr,
+ &attr_ppe_temperature1.attr,
+};
+
+static struct attribute_group ppe_attribute_group = {
+ .name = "thermal",
+ .attrs = ppe_attributes,
+};
+
+/*
+ * initialize throttling with default values
+ */
+static void __init init_default_values(void)
+{
+ int cpu;
+ struct cbe_pmd_regs __iomem *pmd_regs;
+ struct sys_device *sysdev;
+ union ppe_spe_reg tpr;
+ union spe_reg str1;
+ u64 str2;
+ union spe_reg cr1;
+ u64 cr2;
+
+ /* TPR defaults */
+ /* ppe
+ * 1F - no full stop
+ * 08 - dynamic throttling starts if over 80 degrees
+ * 03 - dynamic throttling ceases if below 70 degrees */
+ tpr.ppe = 0x1F0803;
+ /* spe
+ * 10 - full stopped when over 96 degrees
+ * 08 - dynamic throttling starts if over 80 degrees
+ * 03 - dynamic throttling ceases if below 70 degrees
+ */
+ tpr.spe = 0x100803;
+
+ /* STR defaults */
+ /* str1
+ * 10 - stop 16 of 32 cycles
+ */
+ str1.val = 0x1010101010101010ull;
+ /* str2
+ * 10 - stop 16 of 32 cycles
+ */
+ str2 = 0x10;
+
+ /* CR defaults */
+ /* cr1
+ * 4 - normal operation
+ */
+ cr1.val = 0x0404040404040404ull;
+ /* cr2
+ * 4 - normal operation
+ */
+ cr2 = 0x04;
+
+ for_each_possible_cpu (cpu) {
+ pr_debug("processing cpu %d\n", cpu);
+ sysdev = get_cpu_sysdev(cpu);
+ pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
+
+ out_be64(&pmd_regs->tm_str2, str2);
+ out_be64(&pmd_regs->tm_str1.val, str1.val);
+ out_be64(&pmd_regs->tm_tpr.val, tpr.val);
+ out_be64(&pmd_regs->tm_cr1.val, cr1.val);
+ out_be64(&pmd_regs->tm_cr2, cr2);
+ }
+}
+
+
+static int __init thermal_init(void)
+{
+ init_default_values();
+
+ spu_add_sysdev_attr_group(&spu_attribute_group);
+ cpu_add_sysdev_attr_group(&ppe_attribute_group);
+
+ return 0;
+}
+module_init(thermal_init);
+
+static void __exit thermal_exit(void)
+{
+ spu_remove_sysdev_attr_group(&spu_attribute_group);
+ cpu_remove_sysdev_attr_group(&ppe_attribute_group);
+}
+module_exit(thermal_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
+
--
^ permalink raw reply
* [PATCH 13/16] cell: use ppc_md->power_save instead of cbe_idle_loop
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
This moves the cell idle function to use the default cpu_idle
with a special power_save callback, like all other platforms
except iSeries already do.
It also makes it possible to disable this power_save function
with a new powerpc-specific boot option "powersave=off".
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/kernel/idle.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/idle.c
+++ linux-2.6/arch/powerpc/kernel/idle.c
@@ -39,6 +39,13 @@
#define cpu_should_die() 0
#endif
+static int __init powersave_off(char *arg)
+{
+ ppc_md.power_save = NULL;
+ return 0;
+}
+__setup("powersave=off", powersave_off);
+
/*
* The body of the idle task.
*/
Index: linux-2.6/arch/powerpc/platforms/cell/pervasive.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/pervasive.c
+++ linux-2.6/arch/powerpc/platforms/cell/pervasive.c
@@ -38,32 +38,16 @@
#include "pervasive.h"
#include "cbe_regs.h"
-static DEFINE_SPINLOCK(cbe_pervasive_lock);
-
-static void __init cbe_enable_pause_zero(void)
+static void cbe_power_save(void)
{
- unsigned long thread_switch_control;
- unsigned long temp_register;
- struct cbe_pmd_regs __iomem *pregs;
-
- spin_lock_irq(&cbe_pervasive_lock);
- pregs = cbe_get_cpu_pmd_regs(smp_processor_id());
- if (pregs == NULL)
- goto out;
-
- pr_debug("Power Management: CPU %d\n", smp_processor_id());
-
- /* Enable Pause(0) control bit */
- temp_register = in_be64(&pregs->pmcr);
-
- out_be64(&pregs->pmcr,
- temp_register | CBE_PMD_PAUSE_ZERO_CONTROL);
+ unsigned long ctrl, thread_switch_control;
+ ctrl = mfspr(SPRN_CTRLF);
/* Enable DEC and EE interrupt request */
thread_switch_control = mfspr(SPRN_TSC_CELL);
thread_switch_control |= TSC_CELL_EE_ENABLE | TSC_CELL_EE_BOOST;
- switch ((mfspr(SPRN_CTRLF) & CTRL_CT)) {
+ switch (ctrl & CTRL_CT) {
case CTRL_CT0:
thread_switch_control |= TSC_CELL_DEC_ENABLE_0;
break;
@@ -75,58 +59,21 @@ static void __init cbe_enable_pause_zero
__FUNCTION__);
break;
}
-
mtspr(SPRN_TSC_CELL, thread_switch_control);
-out:
- spin_unlock_irq(&cbe_pervasive_lock);
-}
-
-static void cbe_idle(void)
-{
- unsigned long ctrl;
-
- /* Why do we do that on every idle ? Couldn't that be done once for
- * all or do we lose the state some way ? Also, the pmcr
- * register setting, that can't be set once at boot ? We really want
- * to move that away in order to implement a simple powersave
+ /*
+ * go into low thread priority, medium priority will be
+ * restored for us after wake-up.
*/
- cbe_enable_pause_zero();
+ HMT_low();
- while (1) {
- if (!need_resched()) {
- local_irq_disable();
- while (!need_resched()) {
- /* go into low thread priority */
- HMT_low();
-
- /*
- * atomically disable thread execution
- * and runlatch.
- * External and Decrementer exceptions
- * are still handled when the thread
- * is disabled but now enter in
- * cbe_system_reset_exception()
- */
- ctrl = mfspr(SPRN_CTRLF);
- ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
- mtspr(SPRN_CTRLT, ctrl);
- }
- /* restore thread prio */
- HMT_medium();
- local_irq_enable();
- }
-
- /*
- * turn runlatch on again before scheduling the
- * process we just woke up
- */
- ppc64_runlatch_on();
-
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
+ /*
+ * atomically disable thread execution and runlatch.
+ * External and Decrementer exceptions are still handled when the
+ * thread is disabled but now enter in cbe_system_reset_exception()
+ */
+ ctrl &= ~(CTRL_RUNLATCH | CTRL_TE);
+ mtspr(SPRN_CTRLT, ctrl);
}
static int cbe_system_reset_exception(struct pt_regs *regs)
@@ -158,9 +105,20 @@ static int cbe_system_reset_exception(st
void __init cbe_pervasive_init(void)
{
+ int cpu;
if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO))
return;
- ppc_md.idle_loop = cbe_idle;
+ for_each_possible_cpu(cpu) {
+ struct cbe_pmd_regs __iomem *regs = cbe_get_cpu_pmd_regs(cpu);
+ if (!regs)
+ continue;
+
+ /* Enable Pause(0) control bit */
+ out_be64(®s->pmcr, in_be64(®s->pmcr) |
+ CBE_PMD_PAUSE_ZERO_CONTROL);
+ }
+
+ ppc_md.power_save = cbe_power_save;
ppc_md.system_reset_exception = cbe_system_reset_exception;
}
--
^ permalink raw reply
* [PATCH 14/16] add support for stopping spus from xmon
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Michael Ellerman <michael@ellerman.id.au>
This patch adds support for stopping, and restarting, spus
from xmon. We use the spu master runcntl bit to stop execution,
this is apparently the "right" way to control spu execution and
spufs will be changed in the future to use this bit.
Testing has shown that to restart execution we have to turn the
master runcntl bit on and also rewrite the spu runcntl bit, even
if it is already set to 1 (running).
Stopping spus is triggered by the xmon command 'ss' - "spus stop"
perhaps. Restarting them is triggered via 'sr'. Restart doesn't
start execution on spus unless they were running prior to being
stopped by xmon.
Walking the spu->full_list in xmon after a panic, would mean
corruption of any spu struct would make all the others
inaccessible. To avoid this, and also to make the next patch
easier, we cache pointers to all spus during boot.
We attempt to catch and recover from errors while stopping and
restarting the spus, but as with most xmon functionality there are
no guarantees that performing these operations won't crash xmon
itself.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
arch/powerpc/platforms/cell/spu_base.c | 4
arch/powerpc/xmon/xmon.c | 142 ++++++++++++++++++++++++++++++++-
include/asm-powerpc/xmon.h | 2
3 files changed, 146 insertions(+), 2 deletions(-)
Index: linux-2.6/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/spu_base.c
+++ linux-2.6/arch/powerpc/platforms/cell/spu_base.c
@@ -38,6 +38,7 @@
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/mmu_context.h>
+#include <asm/xmon.h>
#include "interrupt.h"
@@ -943,6 +944,9 @@ static int __init init_spu_base(void)
break;
}
}
+
+ xmon_register_spus(&spu_full_list);
+
return ret;
}
module_init(init_spu_base);
Index: linux-2.6/arch/powerpc/xmon/xmon.c
===================================================================
--- linux-2.6.orig/arch/powerpc/xmon/xmon.c
+++ linux-2.6/arch/powerpc/xmon/xmon.c
@@ -37,6 +37,8 @@
#include <asm/sstep.h>
#include <asm/bug.h>
#include <asm/irq_regs.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
@@ -147,6 +149,8 @@ static void xmon_print_symbol(unsigned l
const char *after);
static const char *getvecname(unsigned long vec);
+static int do_spu_cmd(void);
+
int xmon_no_auto_backtrace;
extern int print_insn_powerpc(unsigned long, unsigned long, int);
@@ -209,8 +213,12 @@ Commands:\n\
mi show information about memory allocation\n\
p call a procedure\n\
r print registers\n\
- s single step\n\
- S print special registers\n\
+ s single step\n"
+#ifdef CONFIG_PPC_CELL
+" ss stop execution on all spus\n\
+ sr restore execution on stopped spus\n"
+#endif
+" S print special registers\n\
t print backtrace\n\
x exit monitor and recover\n\
X exit monitor and dont recover\n"
@@ -518,6 +526,7 @@ int xmon(struct pt_regs *excp)
xmon_save_regs(®s);
excp = ®s;
}
+
return xmon_core(excp, 0);
}
EXPORT_SYMBOL(xmon);
@@ -809,6 +818,8 @@ cmds(struct pt_regs *excp)
cacheflush();
break;
case 's':
+ if (do_spu_cmd() == 0)
+ break;
if (do_step(excp))
return cmd;
break;
@@ -2630,3 +2641,130 @@ void __init xmon_setup(void)
if (xmon_early)
debugger(NULL);
}
+
+#ifdef CONFIG_PPC_CELL
+
+struct spu_info {
+ struct spu *spu;
+ u64 saved_mfc_sr1_RW;
+ u32 saved_spu_runcntl_RW;
+ u8 stopped_ok;
+};
+
+#define XMON_NUM_SPUS 16 /* Enough for current hardware */
+
+static struct spu_info spu_info[XMON_NUM_SPUS];
+
+void xmon_register_spus(struct list_head *list)
+{
+ struct spu *spu;
+
+ list_for_each_entry(spu, list, full_list) {
+ if (spu->number >= XMON_NUM_SPUS) {
+ WARN_ON(1);
+ continue;
+ }
+
+ spu_info[spu->number].spu = spu;
+ spu_info[spu->number].stopped_ok = 0;
+ }
+}
+
+static void stop_spus(void)
+{
+ struct spu *spu;
+ int i;
+ u64 tmp;
+
+ for (i = 0; i < XMON_NUM_SPUS; i++) {
+ if (!spu_info[i].spu)
+ continue;
+
+ if (setjmp(bus_error_jmp) == 0) {
+ catch_memory_errors = 1;
+ sync();
+
+ spu = spu_info[i].spu;
+
+ spu_info[i].saved_spu_runcntl_RW =
+ in_be32(&spu->problem->spu_runcntl_RW);
+
+ tmp = spu_mfc_sr1_get(spu);
+ spu_info[i].saved_mfc_sr1_RW = tmp;
+
+ tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+ spu_mfc_sr1_set(spu, tmp);
+
+ sync();
+ __delay(200);
+
+ spu_info[i].stopped_ok = 1;
+ printf("Stopped spu %.2d\n", i);
+ } else {
+ catch_memory_errors = 0;
+ printf("*** Error stopping spu %.2d\n", i);
+ }
+ catch_memory_errors = 0;
+ }
+}
+
+static void restart_spus(void)
+{
+ struct spu *spu;
+ int i;
+
+ for (i = 0; i < XMON_NUM_SPUS; i++) {
+ if (!spu_info[i].spu)
+ continue;
+
+ if (!spu_info[i].stopped_ok) {
+ printf("*** Error, spu %d was not successfully stopped"
+ ", not restarting\n", i);
+ continue;
+ }
+
+ if (setjmp(bus_error_jmp) == 0) {
+ catch_memory_errors = 1;
+ sync();
+
+ spu = spu_info[i].spu;
+ spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
+ out_be32(&spu->problem->spu_runcntl_RW,
+ spu_info[i].saved_spu_runcntl_RW);
+
+ sync();
+ __delay(200);
+
+ printf("Restarted spu %.2d\n", i);
+ } else {
+ catch_memory_errors = 0;
+ printf("*** Error restarting spu %.2d\n", i);
+ }
+ catch_memory_errors = 0;
+ }
+}
+
+static int do_spu_cmd(void)
+{
+ int cmd;
+
+ cmd = inchar();
+ switch (cmd) {
+ case 's':
+ stop_spus();
+ break;
+ case 'r':
+ restart_spus();
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#else /* ! CONFIG_PPC_CELL */
+static int do_spu_cmd(void)
+{
+ return -1;
+}
+#endif
Index: linux-2.6/include/asm-powerpc/xmon.h
===================================================================
--- linux-2.6.orig/include/asm-powerpc/xmon.h
+++ linux-2.6/include/asm-powerpc/xmon.h
@@ -14,8 +14,10 @@
#ifdef CONFIG_XMON
extern void xmon_setup(void);
+extern void xmon_register_spus(struct list_head *list);
#else
static inline void xmon_setup(void) { };
+static inline void xmon_register_spus(struct list_head *list) { };
#endif
#endif /* __KERNEL __ */
--
^ permalink raw reply
* [PATCH 15/16] add support for dumping spu info from xmon
From: arnd @ 2006-10-24 16:31 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus; +Cc: Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Michael Ellerman <michael@ellerman.id.au>
This patch adds a command to xmon for dumping information about
spu structs. The command is 'sf' for "spu fields" perhaps, and
takes the spu number as an argument. This is the same value as the
spu->number field, or the "phys-id" value of a context when it is
bound to a physical spu.
We try to catch memory errors as we dump each field, hopefully this
will make the command reasonably robust, but YMMV. If people see a
need we can easily add more fields to the dump in future.
Output looks something like this:
0:mon> sf 0
Dumping spu fields at address c00000001ffd9e80:
number = 0x0
name = spe
devnode->full_name = /cpus/PowerPC,BE@0/spes/spe@0
nid = 0x0
local_store_phys = 0x20000000000
local_store = 0xd0000800801e0000
ls_size = 0x0
isrc = 0x4
node = 0x0
flags = 0x0
dar = 0x0
dsisr = 0x0
class_0_pending = 0
irqs[0] = 0x16
irqs[1] = 0x17
irqs[2] = 0x24
slb_replace = 0x0
pid = 0
prio = 0
mm = 0x0000000000000000
ctx = 0x0000000000000000
rq = 0x0000000000000000
timestamp = 0x0000000000000000
problem_phys = 0x20000040000
problem = 0xd000080080220000
problem->spu_runcntl_RW = 0x0
problem->spu_status_R = 0x0
problem->spu_npc_RW = 0x0
priv1 = 0xd000080080240000
priv1->mfc_sr1_RW = 0x33
priv2 = 0xd000080080250000
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
---
arch/powerpc/xmon/xmon.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
Index: linux-2.6/arch/powerpc/xmon/xmon.c
===================================================================
--- linux-2.6.orig/arch/powerpc/xmon/xmon.c
+++ linux-2.6/arch/powerpc/xmon/xmon.c
@@ -216,7 +216,8 @@ Commands:\n\
s single step\n"
#ifdef CONFIG_PPC_CELL
" ss stop execution on all spus\n\
- sr restore execution on stopped spus\n"
+ sr restore execution on stopped spus\n\
+ sf # dump spu fields for spu # (in hex)\n"
#endif
" S print special registers\n\
t print backtrace\n\
@@ -2744,8 +2745,66 @@ static void restart_spus(void)
}
}
+#define DUMP_WIDTH 23
+#define DUMP_FIELD(obj, format, field) \
+do { \
+ if (setjmp(bus_error_jmp) == 0) { \
+ catch_memory_errors = 1; \
+ sync(); \
+ printf(" %-*s = "format"\n", DUMP_WIDTH, \
+ #field, obj->field); \
+ sync(); \
+ __delay(200); \
+ } else { \
+ catch_memory_errors = 0; \
+ printf(" %-*s = *** Error reading field.\n", \
+ DUMP_WIDTH, #field); \
+ } \
+ catch_memory_errors = 0; \
+} while (0)
+
+static void dump_spu_fields(struct spu *spu)
+{
+ printf("Dumping spu fields at address %p:\n", spu);
+
+ DUMP_FIELD(spu, "0x%x", number);
+ DUMP_FIELD(spu, "%s", name);
+ DUMP_FIELD(spu, "%s", devnode->full_name);
+ DUMP_FIELD(spu, "0x%x", nid);
+ DUMP_FIELD(spu, "0x%lx", local_store_phys);
+ DUMP_FIELD(spu, "0x%p", local_store);
+ DUMP_FIELD(spu, "0x%lx", ls_size);
+ DUMP_FIELD(spu, "0x%x", node);
+ DUMP_FIELD(spu, "0x%lx", flags);
+ DUMP_FIELD(spu, "0x%lx", dar);
+ DUMP_FIELD(spu, "0x%lx", dsisr);
+ DUMP_FIELD(spu, "%d", class_0_pending);
+ DUMP_FIELD(spu, "0x%lx", irqs[0]);
+ DUMP_FIELD(spu, "0x%lx", irqs[1]);
+ DUMP_FIELD(spu, "0x%lx", irqs[2]);
+ DUMP_FIELD(spu, "0x%x", slb_replace);
+ DUMP_FIELD(spu, "%d", pid);
+ DUMP_FIELD(spu, "%d", prio);
+ DUMP_FIELD(spu, "0x%p", mm);
+ DUMP_FIELD(spu, "0x%p", ctx);
+ DUMP_FIELD(spu, "0x%p", rq);
+ DUMP_FIELD(spu, "0x%p", timestamp);
+ DUMP_FIELD(spu, "0x%lx", problem_phys);
+ DUMP_FIELD(spu, "0x%p", problem);
+ DUMP_FIELD(spu, "0x%x", problem->spu_runcntl_RW);
+ DUMP_FIELD(spu, "0x%x", problem->spu_status_R);
+ DUMP_FIELD(spu, "0x%x", problem->spu_npc_RW);
+ DUMP_FIELD(spu, "0x%p", priv1);
+
+ if (spu->priv1)
+ DUMP_FIELD(spu, "0x%lx", priv1->mfc_sr1_RW);
+
+ DUMP_FIELD(spu, "0x%p", priv2);
+}
+
static int do_spu_cmd(void)
{
+ unsigned long num = 0;
int cmd;
cmd = inchar();
@@ -2756,6 +2815,12 @@ static int do_spu_cmd(void)
case 'r':
restart_spus();
break;
+ case 'f':
+ if (scanhex(&num) && num < XMON_NUM_SPUS && spu_info[num].spu)
+ dump_spu_fields(spu_info[num].spu);
+ else
+ printf("*** Error: invalid spu number\n");
+ break;
default:
return -1;
}
--
^ permalink raw reply
* [PATCH 16/16] cell: add cpufreq driver for Cell BE processor
From: arnd @ 2006-10-24 16:39 UTC (permalink / raw)
To: cbe-oss-dev, linuxppc-dev, linux-kernel, paulus
Cc: Christian Krafft, Arnd Bergmann
In-Reply-To: <20061024163113.694643000@arndb.de>
From: Christian Krafft <krafft@de.ibm.com>
This patch adds a cpufreq backend driver to enable frequency scaling on cell.
Signed-off-by: Christian Krafft <krafft@de.ibm.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Index: linux-2.6/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Kconfig
+++ linux-2.6/arch/powerpc/platforms/cell/Kconfig
@@ -25,4 +25,13 @@ config CBE_THERM
default m
depends on CBE_RAS
+config CBE_CPUFREQ
+ tristate "CBE frequency scaling"
+ depends on CBE_RAS && CPU_FREQ
+ default m
+ help
+ This adds the cpufreq driver for Cell BE processors.
+ For details, take a look at <file:Documentation/cpu-freq/>.
+ If you don't have such processor, say N
+
endmenu
Index: linux-2.6/arch/powerpc/platforms/cell/Makefile
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/cell/Makefile
+++ linux-2.6/arch/powerpc/platforms/cell/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += interr
obj-$(CONFIG_CBE_RAS) += ras.o
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
+obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o
ifeq ($(CONFIG_SMP),y)
obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
Index: linux-2.6/arch/powerpc/platforms/cell/cbe_cpufreq.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -0,0 +1,248 @@
+/*
+ * cpufreq driver for the cell processor
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/timer.h>
+
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+#include "cbe_regs.h"
+
+static DEFINE_MUTEX(cbe_switch_mutex);
+
+
+/* the CBE supports an 8 step frequency scaling */
+static struct cpufreq_frequency_table cbe_freqs[] = {
+ {1, 0},
+ {2, 0},
+ {3, 0},
+ {4, 0},
+ {5, 0},
+ {6, 0},
+ {8, 0},
+ {10, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+ [0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+ 0x0000240000000000ull,
+ 0x0000268000000000ull,
+ 0x000029C000000000ull,
+ 0x00002D0000000000ull,
+ 0x0000300000000000ull,
+ 0x0000334000000000ull,
+ 0x000039C000000000ull,
+ 0x00003FC000000000ull,
+};
+
+/*
+ * hardware specific functions
+ */
+
+static int get_pmode(int cpu)
+{
+ int ret;
+ struct cbe_pmd_regs __iomem *pmd_regs;
+
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+ ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+ return ret;
+}
+
+static int set_pmode(int cpu, unsigned int pmode)
+{
+ struct cbe_pmd_regs __iomem *pmd_regs;
+ struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+ u64 flags;
+ u64 value;
+
+ local_irq_save(flags);
+
+ mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+ pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
+ pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
+
+ out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+ out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+ out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+ out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+ value = in_be64(&pmd_regs->pmcr);
+ /* set bits to zero */
+ value &= 0xFFFFFFFFFFFFFFF8ull;
+ /* set bits to next pmode */
+ value |= pmode;
+
+ out_be64(&pmd_regs->pmcr, value);
+
+ /* wait until new pmode appears in status register */
+ value = in_be64(&pmd_regs->pmsr) & 0x07;
+ while(value != pmode) {
+ cpu_relax();
+ value = in_be64(&pmd_regs->pmsr) & 0x07;
+ }
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+{
+ u32 *max_freq;
+ int i, cur_pmode;
+ struct device_node *cpu;
+
+ cpu = of_get_cpu_node(policy->cpu, NULL);
+
+ if(!cpu)
+ return -ENODEV;
+
+ pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+
+ max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+
+ if(!max_freq)
+ return -EINVAL;
+
+ // we need the freq in kHz
+ *max_freq /= 1000;
+
+ pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+ pr_debug("initializing frequency table\n");
+
+ // initialize frequency table
+ for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
+ cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+ pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
+ }
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+ policy->cpuinfo.transition_latency = 25000;
+
+ cur_pmode = get_pmode(policy->cpu);
+ pr_debug("current pmode is at %d\n",cur_pmode);
+
+ policy->cur = cbe_freqs[cur_pmode].frequency;
+
+#ifdef CONFIG_SMP
+ policy->cpus = cpu_sibling_map[policy->cpu];
+#endif
+
+ cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+
+ /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+ return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+}
+
+static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, cbe_freqs);
+}
+
+
+static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
+ unsigned int relation)
+{
+ int rc;
+ struct cpufreq_freqs freqs;
+ int cbe_pmode_new;
+
+ cpufreq_frequency_table_target(policy,
+ cbe_freqs,
+ target_freq,
+ relation,
+ &cbe_pmode_new);
+
+ freqs.old = policy->cur;
+ freqs.new = cbe_freqs[cbe_pmode_new].frequency;
+ freqs.cpu = policy->cpu;
+
+ mutex_lock (&cbe_switch_mutex);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+ policy->cpu,
+ cbe_freqs[cbe_pmode_new].frequency,
+ cbe_freqs[cbe_pmode_new].index);
+
+ rc = set_pmode(policy->cpu, cbe_pmode_new);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&cbe_switch_mutex);
+
+ return rc;
+}
+
+static struct cpufreq_driver cbe_cpufreq_driver = {
+ .verify = cbe_cpufreq_verify,
+ .target = cbe_cpufreq_target,
+ .init = cbe_cpufreq_cpu_init,
+ .exit = cbe_cpufreq_cpu_exit,
+ .name = "cbe-cpufreq",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+};
+
+/*
+ * module init and destoy
+ */
+
+static int __init cbe_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&cbe_cpufreq_driver);
+}
+
+static void __exit cbe_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&cbe_cpufreq_driver);
+}
+
+module_init(cbe_cpufreq_init);
+module_exit(cbe_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
Index: linux-2.6/arch/powerpc/configs/cell_defconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/configs/cell_defconfig
+++ linux-2.6/arch/powerpc/configs/cell_defconfig
@@ -139,7 +139,19 @@ CONFIG_RTAS_FLASH=y
CONFIG_MMIO_NVRAM=y
# CONFIG_PPC_MPC106 is not set
# CONFIG_PPC_970_NAP is not set
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_CPU_FREQ_DEBUG=y
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+# CONFIG_CPU_FREQ_PMAC64 is not set
# CONFIG_WANT_EARLY_SERIAL is not set
# CONFIG_MPIC is not set
@@ -150,6 +162,7 @@ CONFIG_SPU_FS=m
CONFIG_SPU_BASE=y
CONFIG_CBE_RAS=y
CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
#
# Kernel options
Index: linux-2.6/arch/powerpc/kernel/prom.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/prom.c
+++ linux-2.6/arch/powerpc/kernel/prom.c
@@ -1672,6 +1672,7 @@ struct device_node *of_get_cpu_node(int
}
return NULL;
}
+EXPORT_SYMBOL(of_get_cpu_node);
#ifdef DEBUG
static struct debugfs_blob_wrapper flat_dt_blob;
Index: linux-2.6/arch/powerpc/kernel/smp.c
===================================================================
--- linux-2.6.orig/arch/powerpc/kernel/smp.c
+++ linux-2.6/arch/powerpc/kernel/smp.c
@@ -65,6 +65,7 @@ cpumask_t cpu_sibling_map[NR_CPUS] = { [
EXPORT_SYMBOL(cpu_online_map);
EXPORT_SYMBOL(cpu_possible_map);
+EXPORT_SYMBOL(cpu_sibling_map);
/* SMP operations for this machine */
struct smp_ops_t *smp_ops;
--
^ permalink raw reply
* Re: MPC834x TSECs/Gianfar w/o MDIO accessible PHYs
From: Andy Fleming @ 2006-10-24 18:15 UTC (permalink / raw)
To: KRONSTORFER Horst; +Cc: linuxppc-embedded
In-Reply-To: <CAB1644F1C94A24BAC68B05D0F9774635CC446@VIECLEX01.frequentis.frq>
Look at the driver in drivers/net/phy/fixed.c. It probably needs
some documentation, and Vitaly implied it needed a little tweaking,
but it provides the basics of what you need (and what Dan
mentioned). Essentially, you need to fake the PHY. However, if you
wanted, you could also get smarter and write a new mdiobus driver,
which handles configuring and using the switch.
I'm not quite sure why your approach isn't working, but I agree with
Dan's suspicions that removing the PHY code doesn't just work.
One thing to check is the adjust_link() function. You need to make
sure that you have the carrier on, and that the MAC is set to MII
mode, rather than GMII mode.
Andy
On Oct 24, 2006, at 04:16, KRONSTORFER Horst wrote:
> hi!
>
> in our design we use an mpc8343 with the 2 tsecs connected to a
> zarlink zl50411 eth switch in mii mode. the 2 ports of the switch
> are running in phy mode (reverse mii) w/o mdio. we're currently
> running kernel 2.6.17.13.
>
> i therefore 'simply' removed the mdio bus and phy support and tested
> with ping over tsec0. result: i can see arp requests which are some-
> what malformed (dest mac addr is not bcast, source ip addr is
> incorrect,
> etc ...) btw: i used the same approach in u-boot and it works fine.
>
> i then checked the content of the sk_buff handed over to
> gfar_start_xmit
> which is correct (mac addrs, ip addrs, ...)
>
> i'm currently out of ideas, any kind of help is appreciated!
>
> thanks
> -h
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: [PATCH 2/3] spufs: fix another off-by-one bug in mbox_read
From: Pekka Enberg @ 2006-10-24 18:42 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Arnd Bergmann, linuxppc-dev, Paul Mackerras, cbe-oss-dev,
linux-kernel
In-Reply-To: <20061024160406.923275000@arndb.de>
Hi Arnd,
On 10/24/06, Arnd Bergmann <arnd@arndb.de> wrote:
> spu_acquire(ctx);
> - for (count = 0; count <= len; count += 4, udata++) {
> + for (count = 0; (count + 4) <= len; count += 4, udata++) {
Wouldn't this be more obvious as
for (count = 0, count < (len / 4); count++, udata++) {
And then do count * 4 if you need the actual index somewhere. Hmm?
^ permalink raw reply
* Re: [PATCH 2/3] spufs: fix another off-by-one bug in mbox_read
From: Arnd Bergmann @ 2006-10-24 19:07 UTC (permalink / raw)
To: Pekka Enberg
Cc: linuxppc-dev, Paul Mackerras, cbe-oss-dev, Arnd Bergmann,
linux-kernel
In-Reply-To: <84144f020610241142y2c86485dj898f555174803577@mail.gmail.com>
On Tuesday 24 October 2006 20:42, Pekka Enberg wrote:
> On 10/24/06, Arnd Bergmann <arnd@arndb.de> wrote:
> > =A0 =A0 =A0 =A0 spu_acquire(ctx);
> > - =A0 =A0 =A0 for (count =3D 0; count <=3D len; count +=3D 4, udata++) {
> > + =A0 =A0 =A0 for (count =3D 0; (count + 4) <=3D len; count +=3D 4, uda=
ta++) {
>
> Wouldn't this be more obvious as
>
> =A0 for (count =3D 0, count < (len / 4); count++, udata++) {
>
> And then do count * 4 if you need the actual index somewhere. Hmm?
Count is the return value from a write() file operation. I find it
more readable to update that every time I do one put_user(), to
the exact value, than calculating the return code later.
Arnd <><=20
^ permalink raw reply
* Re: [PATCH 2/3] spufs: fix another off-by-one bug in mbox_read
From: Will Schmidt @ 2006-10-24 19:53 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linuxppc-dev, Pekka Enberg, Paul Mackerras, cbe-oss-dev,
linux-kernel
In-Reply-To: <200610242107.44115.arnd@arndb.de>
On Tue, 2006-24-10 at 21:07 +0200, Arnd Bergmann wrote:
> On Tuesday 24 October 2006 20:42, Pekka Enberg wrote:
> > On 10/24/06, Arnd Bergmann <arnd@arndb.de> wrote:
> > > spu_acquire(ctx);
> > > - for (count = 0; count <= len; count += 4, udata++) {
> > > + for (count = 0; (count + 4) <= len; count += 4, udata++) {
> >
> > Wouldn't this be more obvious as
> >
> > for (count = 0, count < (len / 4); count++, udata++) {
> >
> > And then do count * 4 if you need the actual index somewhere. Hmm?
>
> Count is the return value from a write() file operation. I find it
> more readable to update that every time I do one put_user(), to
> the exact value, than calculating the return code later.
Hey Arnd,
just curiosity.. What was the behavior before this patch? just
leaving a few (0 - 3) characters behind?
>
> Arnd <><
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH 2/3] spufs: fix another off-by-one bug in mbox_read
From: Arnd Bergmann @ 2006-10-24 19:58 UTC (permalink / raw)
To: will_schmidt
Cc: linuxppc-dev, Pekka Enberg, Paul Mackerras, cbe-oss-dev,
linux-kernel
In-Reply-To: <1161719603.8946.84.camel@farscape>
On Tuesday 24 October 2006 21:53, Will Schmidt wrote:
> Hey Arnd,
> =C2=A0 =C2=A0just curiosity.. =C2=A0 What was the behavior before this pa=
tch? =C2=A0 just
> leaving a few (0 - 3) characters behind?
It transfers more bytes than requested on a read. If you asked for
four bytes, you got eight.
Note: one nasty property of this file in spufs is that you can only
read multiples of four bytes in the first place, there is no way to
atomically put back a few bytes into the hardware register, so reading
less than four bytes returns -EINVAL. Asking for more than four
should return the largest possible multiple of four.
Arnd <><
^ permalink raw reply
* Re: [PATCH] powerpc: map 4K iommu pages even on 64K largepage systems
From: Linas Vepstas @ 2006-10-24 20:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Olof Johansson, linuxppc-dev, Paul Mackerras
In-Reply-To: <1161666868.10524.577.camel@localhost.localdomain>
Hi Ben,
The patch tests well; bt there was one change I didn't understand ...
> +++ linux-cell/include/asm-powerpc/iommu.h 2006-10-24 14:58:45.000000000 +1000
> +
> +#define IOMMU_PAGE_SHIFT 12
> +++ linux-cell/include/asm-powerpc/tce.h 2006-10-24 14:59:20.000000000 +1000
>
> #define TCE_SHIFT 12
> #define TCE_PAGE_SIZE (1 << TCE_SHIFT)
> -#define TCE_PAGE_FACTOR (PAGE_SHIFT - TCE_SHIFT)
This is zero now, but if anyone ever changes IOMMU_PAGE_SHIFT to a
value oter than 12, then the below will break:
> +++ linux-cell/arch/powerpc/platforms/pseries/iommu.c 2006-10-24 15:00:07.000000000 +1000
>
> - index <<= TCE_PAGE_FACTOR;
> - npages <<= TCE_PAGE_FACTOR;
since this shift does need to be made, if IOMMU_PAGE_SHIFT != TCE_SHIFT
> +++ linux-cell/arch/powerpc/sysdev/dart.h 2006-10-24 15:01:16.000000000 +1000
>
> #define DART_PAGE_SHIFT 12
> #define DART_PAGE_SIZE (1 << DART_PAGE_SHIFT)
> -#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_PAGE_SHIFT)
I'd argue that the right fix would have been
> +#define DART_PAGE_FACTOR (IOMMU_PAGE_SHIFT - DART_PAGE_SHIFT)
> +++ linux-cell/arch/powerpc/sysdev/dart_iommu.c 2006-10-24 15:01:47.000000000 +1000
>
> - index <<= DART_PAGE_FACTOR;
> - npages <<= DART_PAGE_FACTOR;
And do *not* remove these lines... certainly, they would have to be
put back in if we made iommu_page_size to be a variable in the iommu
table..
--linas
^ permalink raw reply
* Re: [PATCH] powerpc: map 4K iommu pages even on 64K largepage systems
From: Benjamin Herrenschmidt @ 2006-10-24 21:41 UTC (permalink / raw)
To: Linas Vepstas; +Cc: Olof Johansson, linuxppc-dev, Paul Mackerras
In-Reply-To: <20061024200803.GC6360@austin.ibm.com>
On Tue, 2006-10-24 at 15:08 -0500, Linas Vepstas wrote:
> Hi Ben,
>
> The patch tests well; bt there was one change I didn't understand ...
>
> > +++ linux-cell/include/asm-powerpc/iommu.h 2006-10-24 14:58:45.000000000 +1000
> > +
> > +#define IOMMU_PAGE_SHIFT 12
>
>
> > +++ linux-cell/include/asm-powerpc/tce.h 2006-10-24 14:59:20.000000000 +1000
> >
> > #define TCE_SHIFT 12
> > #define TCE_PAGE_SIZE (1 << TCE_SHIFT)
> > -#define TCE_PAGE_FACTOR (PAGE_SHIFT - TCE_SHIFT)
>
> This is zero now, but if anyone ever changes IOMMU_PAGE_SHIFT to a
> value oter than 12, then the below will break:
My point is that we'll probably not change IOMMU_PAGE_SHIFT. The only
thing we might do is to move the shift into the iommu_table structure to
make it per-iommu (in which case the TCE backend will use 4k or 64k
depending on actual HW/FW support for those sizes).
> > +++ linux-cell/arch/powerpc/platforms/pseries/iommu.c 2006-10-24 15:00:07.000000000 +1000
> >
> > - index <<= TCE_PAGE_FACTOR;
> > - npages <<= TCE_PAGE_FACTOR;
>
> since this shift does need to be made, if IOMMU_PAGE_SHIFT != TCE_SHIFT
Which will not happen.
> > +++ linux-cell/arch/powerpc/sysdev/dart.h 2006-10-24 15:01:16.000000000 +1000
> >
> > #define DART_PAGE_SHIFT 12
> > #define DART_PAGE_SIZE (1 << DART_PAGE_SHIFT)
> > -#define DART_PAGE_FACTOR (PAGE_SHIFT - DART_PAGE_SHIFT)
>
> I'd argue that the right fix would have been
>
> > +#define DART_PAGE_FACTOR (IOMMU_PAGE_SHIFT - DART_PAGE_SHIFT)
See my above comment :)
> > +++ linux-cell/arch/powerpc/sysdev/dart_iommu.c 2006-10-24 15:01:47.000000000 +1000
> >
> > - index <<= DART_PAGE_FACTOR;
> > - npages <<= DART_PAGE_FACTOR;
>
> And do *not* remove these lines... certainly, they would have to be
> put back in if we made iommu_page_size to be a variable in the iommu
> table..
No. DART would set the table shift to DART_PAGE_SHIFT, TCE would set it
to TCE_PAGE_SHIFT and the backend would always get natively sized
addresses/counts.
Ben.
^ permalink raw reply
* Re: pci_set_power_state() failure and breaking suspend
From: Benjamin Herrenschmidt @ 2006-10-24 22:40 UTC (permalink / raw)
To: Stefan Richter
Cc: linuxppc-dev list, linux1394-devel, Linux Kernel list, Greg KH
In-Reply-To: <453DFBFF.8040001@s5r6.in-berlin.de>
On Tue, 2006-10-24 at 13:41 +0200, Stefan Richter wrote:
> Benjamin Herrenschmidt wrote:
> > Well, the question is wether we want to make the whole machine suspend
> > fail because there is a 1394 chip that doesn't do PCI PM in or not...
> >
> > I can send patches "fixing" it both ways (just ignoring the result from
> > pci_set_power_state in general, or just ignoring that result on Apple
> > cells).
>
> Yes, what would be the correct way to do this? And if it the latter
> option, should that be implemented in ohci1394 or in pci_set_power_state?
>
> grep says that almost nobody checks the return code of
> pci_set_power_state. But e.g. usb/core/hcd-pci.c does...
Yes, and I think that's bogus too ...
> (Side note: The sole function that ohci1394's suspend and resume hooks
> fulfill right now in mainline is to change power consumption of the
> chip. The IEEE 1394 stack as a whole does not survive suspend + resume
> yet. A still incomplete solution is in linux1394-2.6.git.)
^ permalink raw reply
* Re: [PATCH] General CHRP/MPC5K2 Platform and drivers support - to comment
From: Paul Mackerras @ 2006-10-24 23:01 UTC (permalink / raw)
To: Matt Sealey; +Cc: linuxppc-dev
In-Reply-To: <453E34FB.3030209@genesi-usa.com>
Matt Sealey writes:
> http://www.power.org/news/articles/new_brand/#isa
>
> I'm talking about the one they consolidated from all the different specs
> Freescale, AMCC and IBM had about what makes a PowerPC processor. Since
> POWER is part of it and it's all Power.org now.. they seem to have changed
> the name.
So, are you proposing we drop support for all the PowerPC processors
that don't conform to the recently-published V2.03 ISA? You don't
want 6xx, 7xx, 7xxx, 52xx, etc. supported any more? :) (joke :)
Seriously, the v2.03 ISA covers only IBM's latest POWER processors
(i.e. not POWER3, POWER4, or even POWER5), and Book E processors. We
support a lot more than that.
Paul.
^ permalink raw reply
* Re: [PATCH] powerpc: map 4K iommu pages even on 64K largepage systems
From: Linas Vepstas @ 2006-10-24 23:17 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Olof Johansson, linuxppc-dev, Paul Mackerras
In-Reply-To: <1161726084.10524.622.camel@localhost.localdomain>
On Wed, Oct 25, 2006 at 07:41:23AM +1000, Benjamin Herrenschmidt wrote:
>
> My point is that we'll probably not change IOMMU_PAGE_SHIFT. The only
> thing we might do is to move the shift into the iommu_table structure to
> make it per-iommu (in which case the TCE backend will use 4k or 64k
> depending on actual HW/FW support for those sizes).
OK, right; I don't know why, I didn't see this right wawy.
--linas
^ permalink raw reply
* Re: status of mpc52xx with arch=powerpc?
From: Benjamin Herrenschmidt @ 2006-10-25 1:46 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-embedded
In-Reply-To: <528646bc0610180652u2ee8e8b4xe25d555a59a27c85@mail.gmail.com>
On Wed, 2006-10-18 at 07:52 -0600, Grant Likely wrote:
> On 10/18/06, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > Is someone working on this already?
> >
> > There are some Kconfig entries, but there seems to be no code, at least
> > not in vanilla.
>
> I'm slowly working on it. I've got a .dts written and I've got u-boot
> w/ the fdt patches running on the board. I need to port the 52xx PIC
> driver into arch/powerpc before I attempt to boot.
Can you send me your .dts ? The bplan folks are doing things for their
EFIKA board and I didn't manage to get them to open up publically their
device-tree until the firmware is final and in production :( But I've
got them to change a few things already, and I'd like to make sure
things are in sync.
Regarding devices, I want to move everything to of_platform_device. I
have some patches in progress to make those easier to work with. I'll
send something in the upcoming couple of days as it's all part of some
Cell related work for a new southbridge.
I'm trying to make sure the bplan stuff and whatever you guys come up
with don't conflict.
Ben.
^ permalink raw reply
* [PATCH] powerpc: Fix CHRP platforms with only 8259
From: Benjamin Herrenschmidt @ 2006-10-25 2:54 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev list
On CHRP platforms with only a 8259 controller, we should set the
default IRQ host to the 8259 driver's one for the IRQ probing
fallbacks to work in case the IRQ tree is incorrect (like on
Pegasos for example). Without this fix, we get a bunch of WARN_ON's
during boot.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/platforms/chrp/setup.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/chrp/setup.c 2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/chrp/setup.c 2006-10-25 12:51:18.000000000 +1000
@@ -477,8 +477,10 @@ static void __init chrp_find_8259(void)
" address, polling\n");
i8259_init(pic, chrp_int_ack);
- if (ppc_md.get_irq == NULL)
+ if (ppc_md.get_irq == NULL) {
ppc_md.get_irq = i8259_irq;
+ irq_set_default_host(i8259_get_host());
+ }
if (chrp_mpic != NULL) {
cascade_irq = irq_of_parse_and_map(pic, 0);
if (cascade_irq == NO_IRQ)
Index: linux-cell/arch/powerpc/sysdev/i8259.c
===================================================================
--- linux-cell.orig/arch/powerpc/sysdev/i8259.c 2006-10-09 12:03:33.000000000 +1000
+++ linux-cell/arch/powerpc/sysdev/i8259.c 2006-10-25 12:51:58.000000000 +1000
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/i8259.h>
#include <asm/prom.h>
@@ -224,6 +225,11 @@ static struct irq_host_ops i8259_host_op
.xlate = i8259_host_xlate,
};
+struct irq_host *i8259_get_host(void)
+{
+ return i8259_host;
+}
+
/**
* i8259_init - Initialize the legacy controller
* @node: device node of the legacy PIC (can be NULL, but then, it will match
Index: linux-cell/include/asm-powerpc/i8259.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/i8259.h 2006-10-09 12:03:34.000000000 +1000
+++ linux-cell/include/asm-powerpc/i8259.h 2006-10-25 12:51:18.000000000 +1000
@@ -7,6 +7,7 @@
#ifdef CONFIG_PPC_MERGE
extern void i8259_init(struct device_node *node, unsigned long intack_addr);
extern unsigned int i8259_irq(void);
+extern struct irq_host *i8259_get_host(void);
#else
extern void i8259_init(unsigned long intack_addr, int offset);
extern int i8259_irq(void);
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox