* Re: [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Benjamin Herrenschmidt @ 2007-10-15 9:25 UTC (permalink / raw)
To: Johannes Berg; +Cc: linuxppc-dev
In-Reply-To: <1192437681.3349.12.camel@johannes.berg>
>
> > --- linux-work.orig/include/asm-powerpc/irqflags.h 2007-10-15 17:10:12.000000000 +1000
> > +++ linux-work/include/asm-powerpc/irqflags.h 2007-10-15 17:11:09.000000000 +1000
>
> > /*
> > - * Do the CPU's IRQ-state tracing from assembly code. We call a
> > - * C function, so save all the C-clobbered registers:
> > + * Most of the CPU's IRQ-state tracing is done from assembly code; we
> > + * have to call a C function so call a wrapper that saves all the
> > + * C-clobbered registers.
> > */
>
> That comment is now wrong, it should probably be removed.
Ah yes, it's stale, I'll get rid of it. Thanks.
Ben.
^ permalink raw reply
* Re: [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Johannes Berg @ 2007-10-15 8:41 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <20071015072826.2D541DDE16@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 1086 bytes --]
On Mon, 2007-10-15 at 17:28 +1000, Benjamin Herrenschmidt wrote:
> This adds the low level irq tracing hooks to the powerpc architecture
> needed to enable full lockdep functionality
>
> Some rework from Johannes initial version, removing the asm trampoline that
> isn't needed (thus improving perfs) and fixing a couple of bugs such as
> incorrect initial preempt_count on the softirq alternate stack.
Cool. I always wanted to look into seeing if I could remove that but
never got around to it. Thanks!
> --- linux-work.orig/include/asm-powerpc/irqflags.h 2007-10-15 17:10:12.000000000 +1000
> +++ linux-work/include/asm-powerpc/irqflags.h 2007-10-15 17:11:09.000000000 +1000
> /*
> - * Do the CPU's IRQ-state tracing from assembly code. We call a
> - * C function, so save all the C-clobbered registers:
> + * Most of the CPU's IRQ-state tracing is done from assembly code; we
> + * have to call a C function so call a wrapper that saves all the
> + * C-clobbered registers.
> */
That comment is now wrong, it should probably be removed.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* Re: [PATCH] Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
From: Arnd Bergmann @ 2007-10-15 7:28 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Thomas Gleixner, mingo, Anton Blanchard, linux-kernel
In-Reply-To: <20071015063833.GA15396@kryten>
On Monday 15 October 2007, Anton Blanchard wrote:
> Pull the copy_to_user out of hrtimer_nanosleep and into the callers
> (common_nsleep, sys_nanosleep) in preparation for converting
> compat_sys_nanosleep to use hrtimers.
Looks good, except for two micro-optimization:
> Signed-off-by: Anton Blanchard <anton@samba.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
> @@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct=
timespec __user *rmtp)
> =A0=A0=A0=A0=A0=A0=A0=A0if (!timespec_valid(&tu))
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EINVAL;
> =A0
> -=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_RE=
L, CLOCK_MONOTONIC);
> +=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_R=
EL, CLOCK_MONOTONIC);
> +
> +=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
> +=A0=A0=A0=A0=A0=A0=A0}
> +
> +=A0=A0=A0=A0=A0=A0=A0return ret;
> =A0}
> =A0
If it's common to call sys_nanosleep with a NULL rmtp argument, we could sa=
ve a
few cycles using=20
return hrtimer_nanosleep(&tu, rmtp ? &rmp : NULL, HRTIMER_MODE_REL,
CLOCK_MONOTONIC);
> diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
> index 57efe04..cce8c75 100644
> --- a/kernel/posix-timers.c
> +++ b/kernel/posix-timers.c
> @@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct=
timespec __user *tp)
> =A0static int common_nsleep(const clockid_t which_clock, int flags,
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 =
struct timespec *tsave, struct timespec __user *rmtp)
> =A0{
> -=A0=A0=A0=A0=A0=A0=A0return hrtimer_nanosleep(tsave, rmtp, flags & TIMER=
_ABSTIME ?
> +=A0=A0=A0=A0=A0=A0=A0struct timespec rmt;
> +=A0=A0=A0=A0=A0=A0=A0int ret;
> +
> +=A0=A0=A0=A0=A0=A0=A0ret =3D hrtimer_nanosleep(tsave, &rmt, flags & TIME=
R_ABSTIME ?
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
> =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=
=A0=A0=A0=A0=A0=A0=A0=A0 which_clock);
> +
> +=A0=A0=A0=A0=A0=A0=A0if (ret && rmtp) {
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (copy_to_user(rmtp, &rmt=
, sizeof(*rmtp)))
> +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret=
urn -EFAULT;
> +=A0=A0=A0=A0=A0=A0=A0}
> +
> +=A0=A0=A0=A0=A0=A0=A0return ret;
> =A0}
I think it would be better here to propagate the move to a kernel *rmtp
down to sys_clock_nanosleep so we get the same optimization in
compat_sys_clock_nanosleep. That should probably also be a separate
patch. I can do one if you don't do it first.
Arnd <><
^ permalink raw reply
* [RFC/PATCH 2/2] powerpc: irqtrace support to 64-bit powerpc
From: Benjamin Herrenschmidt @ 2007-10-15 7:28 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1192433296.924212.737979117370.qpush@grosgo>
This adds the low level irq tracing hooks to the powerpc architecture
needed to enable full lockdep functionality
Some rework from Johannes initial version, removing the asm trampoline that
isn't needed (thus improving perfs) and fixing a couple of bugs such as
incorrect initial preempt_count on the softirq alternate stack.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/Kconfig | 9 +++++
arch/powerpc/kernel/entry_64.S | 27 +++++++++++++++
arch/powerpc/kernel/head_64.S | 68 +++++++++++++++++++++++++++++-----------
arch/powerpc/kernel/irq.c | 17 ++++++++--
arch/powerpc/kernel/ppc_ksyms.c | 4 --
arch/powerpc/kernel/setup_64.c | 6 +++
include/asm-powerpc/exception.h | 7 ++--
include/asm-powerpc/hw_irq.h | 13 ++++---
include/asm-powerpc/irqflags.h | 23 ++++++-------
include/asm-powerpc/rwsem.h | 34 +++++++++++++++-----
include/asm-powerpc/spinlock.h | 1
11 files changed, 155 insertions(+), 54 deletions(-)
Index: linux-work/arch/powerpc/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/Kconfig 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/Kconfig 2007-10-15 17:11:09.000000000 +1000
@@ -50,6 +50,15 @@ config STACKTRACE_SUPPORT
bool
default y
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ depends on PPC64
+ default y
+
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
config RWSEM_GENERIC_SPINLOCK
bool
Index: linux-work/arch/powerpc/kernel/irq.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/irq.c 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/irq.c 2007-10-15 17:11:09.000000000 +1000
@@ -114,7 +114,7 @@ static inline void set_soft_enabled(unsi
: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
}
-void local_irq_restore(unsigned long en)
+void raw_local_irq_restore(unsigned long en)
{
/*
* get_paca()->soft_enabled = en;
@@ -175,6 +175,7 @@ void local_irq_restore(unsigned long en)
__hard_irq_enable();
}
+EXPORT_SYMBOL(raw_local_irq_restore);
#endif /* CONFIG_PPC64 */
int show_interrupts(struct seq_file *p, void *v)
@@ -311,8 +312,20 @@ void do_IRQ(struct pt_regs *regs)
handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
+
+ /* Copy the softirq bits in preempt_count so that the
+ * softirq checks work in the hardirq context.
+ */
+ irqtp->preempt_count =
+ (irqtp->preempt_count & ~SOFTIRQ_MASK) |
+ (curtp->preempt_count & SOFTIRQ_MASK);
+
call_handle_irq(irq, desc, irqtp, handler);
irqtp->task = NULL;
+
+ /* Set any flag that may have been set on the
+ * alternate stack
+ */
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
@@ -358,7 +371,7 @@ void irq_ctx_init(void)
memset((void *)softirq_ctx[i], 0, THREAD_SIZE);
tp = softirq_ctx[i];
tp->cpu = i;
- tp->preempt_count = SOFTIRQ_OFFSET;
+ tp->preempt_count = 0;
memset((void *)hardirq_ctx[i], 0, THREAD_SIZE);
tp = hardirq_ctx[i];
Index: linux-work/arch/powerpc/kernel/ppc_ksyms.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/ppc_ksyms.c 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/ppc_ksyms.c 2007-10-15 17:11:09.000000000 +1000
@@ -49,10 +49,6 @@
#include <asm/commproc.h>
#endif
-#ifdef CONFIG_PPC64
-EXPORT_SYMBOL(local_irq_restore);
-#endif
-
#ifdef CONFIG_PPC32
extern void transfer_to_handler(void);
extern void do_IRQ(struct pt_regs *regs);
Index: linux-work/include/asm-powerpc/hw_irq.h
===================================================================
--- linux-work.orig/include/asm-powerpc/hw_irq.h 2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/hw_irq.h 2007-10-15 17:11:09.000000000 +1000
@@ -27,7 +27,7 @@ static inline unsigned long local_get_fl
return flags;
}
-static inline unsigned long local_irq_disable(void)
+static inline unsigned long raw_local_irq_disable(void)
{
unsigned long flags, zero;
@@ -39,14 +39,15 @@ static inline unsigned long local_irq_di
return flags;
}
-extern void local_irq_restore(unsigned long);
+extern void raw_local_irq_restore(unsigned long);
extern void iseries_handle_interrupts(void);
-#define local_irq_enable() local_irq_restore(1)
-#define local_save_flags(flags) ((flags) = local_get_flags())
-#define local_irq_save(flags) ((flags) = local_irq_disable())
+#define raw_local_irq_enable() raw_local_irq_restore(1)
+#define raw_local_save_flags(flags) ((flags) = local_get_flags())
+#define raw_local_irq_save(flags) ((flags) = raw_local_irq_disable())
-#define irqs_disabled() (local_get_flags() == 0)
+#define raw_irqs_disabled() (local_get_flags() == 0)
+#define raw_irqs_disabled_flags(flags) ((flags) == 0)
#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
Index: linux-work/include/asm-powerpc/irqflags.h
===================================================================
--- linux-work.orig/include/asm-powerpc/irqflags.h 2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/irqflags.h 2007-10-15 17:11:09.000000000 +1000
@@ -2,30 +2,29 @@
* include/asm-powerpc/irqflags.h
*
* IRQ flags handling
- *
- * This file gets included from lowlevel asm headers too, to provide
- * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() macros from the lowlevel headers.
*/
#ifndef _ASM_IRQFLAGS_H
#define _ASM_IRQFLAGS_H
+#ifndef __ASSEMBLY__
/*
* Get definitions for raw_local_save_flags(x), etc.
*/
#include <asm-powerpc/hw_irq.h>
+#else
+#ifdef CONFIG_TRACE_IRQFLAGS
/*
- * Do the CPU's IRQ-state tracing from assembly code. We call a
- * C function, so save all the C-clobbered registers:
+ * Most of the CPU's IRQ-state tracing is done from assembly code; we
+ * have to call a C function so call a wrapper that saves all the
+ * C-clobbered registers.
*/
-#ifdef CONFIG_TRACE_IRQFLAGS
-
-#error No support on PowerPC yet for CONFIG_TRACE_IRQFLAGS
-
+#define TRACE_ENABLE_INTS bl .trace_hardirqs_on
+#define TRACE_DISABLE_INTS bl .trace_hardirqs_off
#else
-# define TRACE_IRQS_ON
-# define TRACE_IRQS_OFF
+#define TRACE_ENABLE_INTS
+#define TRACE_DISABLE_INTS
+#endif
#endif
#endif
Index: linux-work/include/asm-powerpc/rwsem.h
===================================================================
--- linux-work.orig/include/asm-powerpc/rwsem.h 2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/rwsem.h 2007-10-15 17:11:09.000000000 +1000
@@ -32,11 +32,21 @@ struct rw_semaphore {
#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
spinlock_t wait_lock;
struct list_head wait_list;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ struct lockdep_map dep_map;
+#endif
};
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+#else
+# define __RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
#define __RWSEM_INITIALIZER(name) \
{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
- LIST_HEAD_INIT((name).wait_list) }
+ LIST_HEAD_INIT((name).wait_list) \
+ __RWSEM_DEP_MAP_INIT(name) }
#define DECLARE_RWSEM(name) \
struct rw_semaphore name = __RWSEM_INITIALIZER(name)
@@ -46,12 +56,15 @@ extern struct rw_semaphore *rwsem_down_w
extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- sem->count = RWSEM_UNLOCKED_VALUE;
- spin_lock_init(&sem->wait_lock);
- INIT_LIST_HEAD(&sem->wait_list);
-}
+extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
+ struct lock_class_key *key);
+
+#define init_rwsem(sem) \
+ do { \
+ static struct lock_class_key __key; \
+ \
+ __init_rwsem((sem), #sem, &__key); \
+ } while (0)
/*
* lock for reading
@@ -78,7 +91,7 @@ static inline int __down_read_trylock(st
/*
* lock for writing
*/
-static inline void __down_write(struct rw_semaphore *sem)
+static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
{
int tmp;
@@ -88,6 +101,11 @@ static inline void __down_write(struct r
rwsem_down_write_failed(sem);
}
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ __down_write_nested(sem, 0);
+}
+
static inline int __down_write_trylock(struct rw_semaphore *sem)
{
int tmp;
Index: linux-work/include/asm-powerpc/spinlock.h
===================================================================
--- linux-work.orig/include/asm-powerpc/spinlock.h 2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/spinlock.h 2007-10-15 17:11:09.000000000 +1000
@@ -19,6 +19,7 @@
*
* (the type definitions are in asm/spinlock_types.h)
*/
+#include <linux/irqflags.h>
#ifdef CONFIG_PPC64
#include <asm/paca.h>
#include <asm/hvcall.h>
Index: linux-work/include/asm-powerpc/exception.h
===================================================================
--- linux-work.orig/include/asm-powerpc/exception.h 2007-10-15 17:10:12.000000000 +1000
+++ linux-work/include/asm-powerpc/exception.h 2007-10-15 17:11:09.000000000 +1000
@@ -232,14 +232,15 @@ BEGIN_FW_FTR_SECTION; \
mfmsr r10; \
ori r10,r10,MSR_EE; \
mtmsrd r10,1; \
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \
+ TRACE_DISABLE_INTS
#else
#define DISABLE_INTS \
li r11,0; \
stb r11,PACASOFTIRQEN(r13); \
- stb r11,PACAHARDIRQEN(r13)
-
+ stb r11,PACAHARDIRQEN(r13); \
+ TRACE_DISABLE_INTS
#endif /* CONFIG_PPC_ISERIES */
#define ENABLE_INTS \
Index: linux-work/arch/powerpc/kernel/head_64.S
===================================================================
--- linux-work.orig/arch/powerpc/kernel/head_64.S 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/head_64.S 2007-10-15 17:11:09.000000000 +1000
@@ -36,8 +36,7 @@
#include <asm/firmware.h>
#include <asm/page_64.h>
#include <asm/exception.h>
-
-#define DO_SOFT_DISABLE
+#include <asm/irqflags.h>
/*
* We layout physical memory as follows:
@@ -450,24 +449,35 @@ bad_stack:
*/
fast_exc_return_irq: /* restores irq state too */
ld r3,SOFTE(r1)
- ld r12,_MSR(r1)
+#ifdef CONFIG_TRACE_IRQFLAGS
+ cmpdi r3,0
+ bne 1f
stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */
+ bl .trace_hardirqs_off
+ b 2f
+1:
+ bl .trace_hardirqs_on
+ li r3,1
+#endif /* CONFIG_TRACE_IRQFLAGS */
+ stb r3,PACASOFTIRQEN(r13) /* restore paca->soft_enabled */
+2:
+ ld r12,_MSR(r1)
rldicl r4,r12,49,63 /* get MSR_EE to LSB */
stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */
- b 1f
+ b 3f
.globl fast_exception_return
fast_exception_return:
ld r12,_MSR(r1)
-1: ld r11,_NIP(r1)
+3: ld r11,_NIP(r1)
andi. r3,r12,MSR_RI /* check if RI is set */
beq- unrecov_fer
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
andi. r3,r12,MSR_PR
- beq 2f
+ beq 4f
ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
+4:
#endif
ld r3,_CCR(r1)
@@ -820,6 +830,25 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
/*
+ * On iSeries, we soft-disable interrupts here, then
+ * hard-enable interrupts so that the hash_page code can spin on
+ * the hash_table_lock without problems on a shared processor.
+ */
+ DISABLE_INTS
+
+ /*
+ * Currently, trace_hardirqs_off() will be called by DISABLE_INTS
+ * and will clobber volatile registers when irq tracing is enabled
+ * so we need to reload them. It may be possible to be smarter here
+ * and move the irq tracing elsewhere but let's keep it simple for
+ * now
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ ld r3,_DAR(r1)
+ ld r4,_DSISR(r1)
+ ld r5,_TRAP(r1)
+#endif /* CONFIG_TRACE_IRQFLAGS */
+ /*
* We need to set the _PAGE_USER bit if MSR_PR is set or if we are
* accessing a userspace segment (even from the kernel). We assume
* kernel addresses always have the high bit set.
@@ -832,13 +861,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */
/*
- * On iSeries, we soft-disable interrupts here, then
- * hard-enable interrupts so that the hash_page code can spin on
- * the hash_table_lock without problems on a shared processor.
- */
- DISABLE_INTS
-
- /*
* r3 contains the faulting address
* r4 contains the required access permissions
* r5 contains the trap number
@@ -848,7 +870,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
bl .hash_page /* build HPTE if possible */
cmpdi r3,0 /* see if hash_page succeeded */
-#ifdef DO_SOFT_DISABLE
BEGIN_FW_FTR_SECTION
/*
* If we had interrupts soft-enabled at the point where the
@@ -860,7 +881,7 @@ BEGIN_FW_FTR_SECTION
*/
beq 13f
END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
+
BEGIN_FW_FTR_SECTION
/*
* Here we have interrupts hard-disabled, so it is sufficient
@@ -874,11 +895,22 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISER
/*
* hash_page couldn't handle it, set soft interrupt enable back
- * to what it was before the trap. Note that .local_irq_restore
+ * to what it was before the trap. Note that .raw_local_irq_restore
* handles any interrupts pending at this point.
*/
ld r3,SOFTE(r1)
- bl .local_irq_restore
+#ifdef CONFIG_TRACE_IRQFLAGS
+ cmpdi r3,0
+ bne 14f
+ bl .raw_local_irq_restore
+ bl .trace_hardirqs_off
+ b 15f
+14:
+ bl .trace_hardirqs_on
+ li r3,1
+#endif /* CONFIG_TRACE_IRQFLAGS */
+ bl .raw_local_irq_restore
+15:
b 11f
/* Here we have a page fault that hash_page can't handle. */
Index: linux-work/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/setup_64.c 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/setup_64.c 2007-10-15 17:11:09.000000000 +1000
@@ -33,6 +33,7 @@
#include <linux/serial_8250.h>
#include <linux/bootmem.h>
#include <linux/pci.h>
+#include <linux/lockdep.h>
#include <asm/io.h>
#include <asm/kdump.h>
#include <asm/prom.h>
@@ -359,6 +360,11 @@ void __init setup_system(void)
&__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
/*
+ * start lockdep
+ */
+ lockdep_init();
+
+ /*
* Unflatten the device-tree passed by prom_init or kexec
*/
unflatten_device_tree();
Index: linux-work/arch/powerpc/kernel/entry_64.S
===================================================================
--- linux-work.orig/arch/powerpc/kernel/entry_64.S 2007-10-15 17:10:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/entry_64.S 2007-10-15 17:13:28.000000000 +1000
@@ -29,6 +29,7 @@
#include <asm/cputable.h>
#include <asm/firmware.h>
#include <asm/bug.h>
+#include <asm/irqflags.h>
/*
* System calls.
@@ -88,6 +89,13 @@ system_call_common:
addi r9,r1,STACK_FRAME_OVERHEAD
ld r11,exception_marker@toc(r2)
std r11,-16(r9) /* "regshere" marker */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_on
+ REST_GPR(0,r1)
+ REST_4GPRS(3,r1)
+ REST_2GPRS(7,r1)
+ addi r9,r1,STACK_FRAME_OVERHEAD
+#endif /* CONFIG_TRACE_IRQFLAGS */
li r10,1
stb r10,PACASOFTIRQEN(r13)
stb r10,PACAHARDIRQEN(r13)
@@ -500,14 +508,27 @@ BEGIN_FW_FTR_SECTION
stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */
ori r10,r10,MSR_EE
mtmsrd r10 /* hard-enable again */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_off
+#endif
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_IRQ
b .ret_from_except_lite /* loop back and handle more */
4:
END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+ cmpdi r5,0
+ bne 5f
stb r5,PACASOFTIRQEN(r13)
-
+ bl .trace_hardirqs_off
+ b 6f
+5:
+ bl .trace_hardirqs_on
+ li r5,1
+#endif
+ stb r5,PACASOFTIRQEN(r13)
+6:
/* extract EE bit and use it to restore paca->hard_enabled */
ld r3,_MSR(r1)
rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */
@@ -574,6 +595,10 @@ do_work:
bne restore
/* here we are preempting the current task */
1:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_on
+ mfmsr r10 /* Get current interrupt state */
+#endif /* CONFIG_TRACE_IRQFLAGS */
li r0,1
stb r0,PACASOFTIRQEN(r13)
stb r0,PACAHARDIRQEN(r13)
^ permalink raw reply
* [RFC/PATCH 1/2] powerpc: lockdep stacktrace support
From: Benjamin Herrenschmidt @ 2007-10-15 7:28 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <1192433296.924212.737979117370.qpush@grosgo>
From: Christoph Hellwig <hch@lst.de>
I recently tried to work on lockdep for powerpc. I have preliminary
version of the stacktrace code, but had to give up on trace irqflags
support because I'm not that knowledgeable on lowlevel ppc details.
Maybe someone more faimilar with the code wants to give it another try?
My stacktrace code is below:
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/Kconfig | 4 +++
arch/powerpc/kernel/Makefile | 1
arch/powerpc/kernel/stacktrace.c | 52 +++++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+)
Index: linux-work/arch/powerpc/Kconfig
===================================================================
--- linux-work.orig/arch/powerpc/Kconfig 2007-10-15 11:19:35.000000000 +1000
+++ linux-work/arch/powerpc/Kconfig 2007-10-15 14:04:05.000000000 +1000
@@ -46,6 +46,10 @@ config IRQ_PER_CPU
bool
default y
+config STACKTRACE_SUPPORT
+ bool
+ default y
+
config RWSEM_GENERIC_SPINLOCK
bool
Index: linux-work/arch/powerpc/kernel/Makefile
===================================================================
--- linux-work.orig/arch/powerpc/kernel/Makefile 2007-10-15 11:19:35.000000000 +1000
+++ linux-work/arch/powerpc/kernel/Makefile 2007-10-15 14:04:05.000000000 +1000
@@ -65,6 +65,7 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o
obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
Index: linux-work/arch/powerpc/kernel/stacktrace.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-work/arch/powerpc/kernel/stacktrace.c 2007-10-15 14:04:05.000000000 +1000
@@ -0,0 +1,52 @@
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+
+
+#ifdef CONFIG_PPC64
+#define MIN_STACK_FRAME 112 /* same as STACK_FRAME_OVERHEAD, in fact */
+#define FRAME_LR_SAVE 2
+#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD + 288)
+#define REGS_MARKER 0x7265677368657265ul
+#define FRAME_MARKER 12
+#else
+#define MIN_STACK_FRAME 16
+#define FRAME_LR_SAVE 1
+#define INT_FRAME_SIZE (sizeof(struct pt_regs) + STACK_FRAME_OVERHEAD)
+#define REGS_MARKER 0x72656773ul
+#define FRAME_MARKER 2
+#endif
+
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ * If all_contexts is set, all contexts (hardirq, softirq and process)
+ * are saved. If not set then only the current context is saved.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+ unsigned long sp;
+
+ asm("mr %0,1" : "=r" (sp));
+
+ for (;;) {
+ unsigned long *stack = (unsigned long *) sp;
+ unsigned long newsp, ip;
+
+ if (!validate_sp(sp, current, MIN_STACK_FRAME))
+ return;
+
+ newsp = stack[0];
+ ip = stack[FRAME_LR_SAVE];
+
+ if (!trace->skip)
+ trace->entries[trace->nr_entries++] = ip;
+ else
+ trace->skip--;
+
+ if (trace->nr_entries >= trace->max_entries)
+ return;
+
+ sp = newsp;
+ }
+}
^ permalink raw reply
* [RFC/PATCH 0/2] powerpc: 64 bits irqtrace / lockdep support
From: Benjamin Herrenschmidt @ 2007-10-15 7:28 UTC (permalink / raw)
To: linuxppc-dev
This is 2 patches, one from Christoph Hellwig that adds the backtrace support,
and one from Johannes Berg modified by me that adds the irq tracing support.
This successfully boots a POWER5 pSeries machine. I'm going to run some more
tests in the upcoming few days, so this is not an official submission (and it's
too late for .24 merge window anyway) but it's looking good so far.
Then, I -might- give a go at a 32 bits version but no promises there :-)
^ permalink raw reply
* [PATCH] Hook compat_sys_nanosleep up to high res timer code
From: Anton Blanchard @ 2007-10-15 6:43 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <20071015063833.GA15396@kryten>
Now we have high res timers on ppc64 I thought Id test them. It turns
out compat_sys_nanosleep hasnt been converted to the hrtimer code and so
is limited to HZ resolution.
The follow patch converts compat_sys_nanosleep to use high res timers.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
diff --git a/kernel/compat.c b/kernel/compat.c
index 3bae374..729f63d 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
-static long compat_nanosleep_restart(struct restart_block *restart)
-{
- unsigned long expire = restart->arg0, now = jiffies;
- struct compat_timespec __user *rmtp;
-
- /* Did it expire while we handled signals? */
- if (!time_after(expire, now))
- return 0;
-
- expire = schedule_timeout_interruptible(expire - now);
- if (expire == 0)
- return 0;
-
- rmtp = (struct compat_timespec __user *)restart->arg1;
- if (rmtp) {
- struct compat_timespec ct;
- struct timespec t;
-
- jiffies_to_timespec(expire, &t);
- ct.tv_sec = t.tv_sec;
- ct.tv_nsec = t.tv_nsec;
- if (copy_to_user(rmtp, &ct, sizeof(ct)))
- return -EFAULT;
- }
- /* The 'restart' block is already filled in */
- return -ERESTART_RESTARTBLOCK;
-}
-
asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
- struct compat_timespec __user *rmtp)
+ struct compat_timespec __user *rmtp)
{
- struct timespec t;
- struct restart_block *restart;
- unsigned long expire;
+ struct timespec tu, rmt;
+ long ret;
- if (get_compat_timespec(&t, rqtp))
+ if (get_compat_timespec(&tu, rqtp))
return -EFAULT;
- if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
+ if (!timespec_valid(&tu))
return -EINVAL;
- expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
- expire = schedule_timeout_interruptible(expire);
- if (expire == 0)
- return 0;
+ ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
- if (rmtp) {
- jiffies_to_timespec(expire, &t);
- if (put_compat_timespec(&t, rmtp))
+ if (ret && rmtp) {
+ if (put_compat_timespec(&rmt, rmtp))
return -EFAULT;
}
- restart = ¤t_thread_info()->restart_block;
- restart->fn = compat_nanosleep_restart;
- restart->arg0 = jiffies + expire;
- restart->arg1 = (unsigned long) rmtp;
- return -ERESTART_RESTARTBLOCK;
+
+ return ret;
}
static inline long get_compat_itimerval(struct itimerval *o,
^ permalink raw reply related
* [PATCH] Rework hrtimer_nanosleep to make sys_compat_nanosleep easier
From: Anton Blanchard @ 2007-10-15 6:38 UTC (permalink / raw)
To: Thomas Gleixner; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <alpine.LFD.0.9999.0710150804290.22612@localhost.localdomain>
Hi Thomas,
Thanks for the review, updates to follow.
Anton
--
Pull the copy_to_user out of hrtimer_nanosleep and into the callers
(common_nsleep, sys_nanosleep) in preparation for converting
compat_sys_nanosleep to use hrtimers.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 540799b..7a9398e 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
/* Precise sleep: */
extern long hrtimer_nanosleep(struct timespec *rqtp,
- struct timespec __user *rmtp,
+ struct timespec *rmtp,
const enum hrtimer_mode mode,
const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index dc8a445..129fead 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{
struct hrtimer_sleeper t;
- struct timespec __user *rmtp;
- struct timespec tu;
+ struct timespec *rmtp;
ktime_t time;
restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
return 0;
- rmtp = (struct timespec __user *) restart->arg1;
+ rmtp = (struct timespec *)restart->arg1;
if (rmtp) {
time = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (time.tv64 <= 0)
return 0;
- tu = ktime_to_timespec(time);
- if (copy_to_user(rmtp, &tu, sizeof(tu)))
- return -EFAULT;
+ *rmtp = ktime_to_timespec(time);
}
restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
return -ERESTART_RESTARTBLOCK;
}
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid)
{
struct restart_block *restart;
struct hrtimer_sleeper t;
- struct timespec tu;
ktime_t rem;
hrtimer_init(&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (rem.tv64 <= 0)
return 0;
- tu = ktime_to_timespec(rem);
- if (copy_to_user(rmtp, &tu, sizeof(tu)))
- return -EFAULT;
+ *rmtp = ktime_to_timespec(rem);
}
restart = ¤t_thread_info()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
asmlinkage long
sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
{
- struct timespec tu;
+ struct timespec tu, rmt;
+ int ret;
if (copy_from_user(&tu, rqtp, sizeof(tu)))
return -EFAULT;
@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
if (!timespec_valid(&tu))
return -EINVAL;
- return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+ ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+
+ if (ret && rmtp) {
+ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+ return -EFAULT;
+ }
+
+ return ret;
}
/*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 57efe04..cce8c75 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)
static int common_nsleep(const clockid_t which_clock, int flags,
struct timespec *tsave, struct timespec __user *rmtp)
{
- return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
+ struct timespec rmt;
+ int ret;
+
+ ret = hrtimer_nanosleep(tsave, &rmt, flags & TIMER_ABSTIME ?
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
which_clock);
+
+ if (ret && rmtp) {
+ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+ return -EFAULT;
+ }
+
+ return ret;
}
asmlinkage long
^ permalink raw reply related
* Re: [PATCH v2 4/7] bestcomm: core bestcomm support for Freescale MPC5200
From: Sven Luther @ 2007-10-15 6:12 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, paulus, domen.puncer
In-Reply-To: <fa686aa40710141423o69666b16pa7ce6851fa407d5e@mail.gmail.com>
On Sun, Oct 14, 2007 at 03:23:21PM -0600, Grant Likely wrote:
> On 10/14/07, Sven Luther <sven@powerlinux.fr> wrote:
> > On Sun, Oct 14, 2007 at 02:22:16PM -0600, Grant Likely wrote:
> > > On 10/14/07, Sven Luther <sven@powerlinux.fr> wrote:
> > > > On Sat, Oct 13, 2007 at 10:42:05PM -0600, Grant Likely wrote:
> > > > > From: Sylvain Munaut <tnt@246tNt.com>
> > > > >
> > > > > This patch adds support for the core of the BestComm API
> > > > > for the Freescale MPC5200(b). The BestComm engine is a
> > > > > microcode-controlled / tasks-based DMA used by several
> > > > > of the onchip devices.
> > > > >
> > > > > Setting up the tasks / memory allocation and all common
> > > > > low level functions are handled by this patch.
> > > > > The specifics details of each tasks and their microcode
> > > > > are split-out in separate patches.
> > > > >
> > > > > This is not the official API, but a much cleaner one.
> > > > > (hopefully)
> > > > >
> > > > > Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
> > > > > Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> > > >
> > > > Hi Grant, ...
> > > >
> > > > I am unsure if this is a regression with regard to Sylvain's patch, or
> > > > somethign else, but it is no more possible to build bestcomm modular :
> > >
> > > Hmmm, interesting. I'll try that out here this afternoon.
> >
> > Notice that domen said it was working, so it could have been a
> > mismanipulation on my part, or some problem with the debian patches.
> >
> > The older patchset with 2.6.23-rc6 worked fine though, and making the
> > main bestcomm module builtin solved the error messages. I did not spot
> > anything obvious when looking at the code.
>
> Yes, it is a regression. There had been a change to the Makefile.
> I've reverted it and it works fine now. I'll repost v3 shortly.
Ok, thanks.
Friendly,
Sven Luther
^ permalink raw reply
* Re: [PATCH] Hook compat_sys_nanosleep up to high res timer code
From: Thomas Gleixner @ 2007-10-15 6:11 UTC (permalink / raw)
To: Anton Blanchard; +Cc: linuxppc-dev, mingo, linux-kernel, Arnd Bergmann
In-Reply-To: <20071014231616.GA24519@kryten>
On Sun, 14 Oct 2007, Anton Blanchard wrote:
> Hi Arnd,
>
> > The code looks correct, but I think it would be nicer to change
> > hrtimer_nanosleep to take a kernel pointer and have all three
> > callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep)
> > do the copy_to_user/put_compat_timespec in the caller.
>
> Good idea, I had considered that but thought a larger cleanup might run
> afoul of the merge rules :)
Looks good, except ....
> --- a/kernel/compat.c
> +++ b/kernel/compat.c
> @@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
> __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
> }
Can you put this into a separate patch please ?
> --- a/kernel/hrtimer.c
> +++ b/kernel/hrtimer.c
> restart = ¤t_thread_info()->restart_block;
> @@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
> asmlinkage long
> sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
> {
> - struct timespec tu;
> + struct timespec tu, rmt;
> + int ret;
>
> if (copy_from_user(&tu, rqtp, sizeof(tu)))
> return -EFAULT;
> @@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
> if (!timespec_valid(&tu))
> return -EINVAL;
>
> - return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
> + ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
> +
> + if (ret) {
Can you check for rmtp as well ? rmtp is optional and can be NULL
> + if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
> + return -EFAULT;
> + }
> +
> + return ret;
> }
>
> /*
> diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
> index 7a15afb..fc7dac2 100644
> --- a/kernel/posix-timers.c
> +++ b/kernel/posix-timers.c
> @@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)
> static int common_nsleep(const clockid_t which_clock, int flags,
> struct timespec *tsave, struct timespec __user *rmtp)
> {
> - return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
> + struct timespec rmt;
> + int ret;
> +
> + ret = hrtimer_nanosleep(tsave, &rmt, flags & TIMER_ABSTIME ?
> HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
> which_clock);
> +
> + if (ret) {
Ditto.
> + if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
> + return -EFAULT;
> + }
> +
> + return ret;
> }
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH] powerpc: Add 1TB workaround for PA6T
From: Michael Neuling @ 2007-10-15 5:25 UTC (permalink / raw)
To: Paul Mackerras; +Cc: Olof Johansson, linuxppc-dev
In-Reply-To: <18194.62797.632192.458851@cargo.ozlabs.ibm.com>
In message <18194.62797.632192.458851@cargo.ozlabs.ibm.com> you wrote:
> Olof Johansson writes:
>
> > @@ -367,7 +368,7 @@ extern void do_feature_fixups(unsigned long value, void
*fixup_start,
> > #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | \
> > CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
> > CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
> > - CPU_FTR_PURR | CPU_FTR_REAL_LE)
> > + CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)
> > #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | \
> > CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
> >
> > @@ -375,7 +376,8 @@ extern void do_feature_fixups(unsigned long value, void
*fixup_start,
> > #define CPU_FTRS_POSSIBLE \
> > (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
> > CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
> > - CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT)
> > + CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT | \
> > + CPU_FTR_NO_SLBIE_B)
> > #else
> > enum {
> > CPU_FTRS_POSSIBLE =
>
> I don't think the second hunk there is necessary, since
> CPU_FTRS_POSSIBLE will already get CPU_FTR_NO_SLBIE_B via
> CPU_FTRS_PA6T.
On that, should we put CPU_FTR_1T_SEGMENT in CPU_FTR_POWER6 and
CPU_FTR_PA6T? Then we can remove it from CPU_FTRS_POSSIBLE also.
Mikey
^ permalink raw reply
* Re: [PATCH 2/2] clk for mpc52xx: use psc_mclk's in spi driver
From: Domen Puncer @ 2007-10-15 5:16 UTC (permalink / raw)
To: Grant Likely; +Cc: david-b, linuxppc-dev
In-Reply-To: <fa686aa40710141542w552eacet7ba13e8e251e2285@mail.gmail.com>
On 14/10/07 16:42 -0600, Grant Likely wrote:
> On 10/14/07, Domen Puncer <domen.puncer@telargo.com> wrote:
> > Use clocks subsystem in spi driver.
>
> I don't understand the advantage of this approach. Is the current code broken?
Actually the calculations are broken. But ok, fix doesn't need to be like this.
And it wasn't my idea to use clk.h :-)
http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=11186
>
> I agree that abstraction is good; but in this case it seems these two
> patches add a lot of code for a very simple calculation. Also, there
> is exactly 2 chips that use these devices, the mpc5200 and the
> mpc5200b, and they are both wired up in exactly the same way. I'm
> inclined to believe that splitting of reading of the CDM into a
> separate driver (or at least using the clk infrastructure) is over the
> edge of diminishing returns. However, I could be convinced that
> having a utility function for setting the PSC clock rate is a useful
> thing, but until arch/ppc goes away, you should support it in both
> arch/ppc and arch/powerpc.
>
> Cheers,
> g.
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
> grant.likely@secretlab.ca
> (403) 399-0195
--
Domen Puncer | Research & Development
.............................................................................................
Telargo d.o.o. | Zagrebška cesta 20 | 2000 Maribor | Slovenia
.............................................................................................
www.telargo.com
^ permalink raw reply
* Re: [PATCH] powerpc: Add 1TB workaround for PA6T
From: Paul Mackerras @ 2007-10-15 5:06 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev
In-Reply-To: <20071012064942.GB30829@lixom.net>
Olof Johansson writes:
> @@ -367,7 +368,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
> #define CPU_FTRS_PA6T (CPU_FTR_USE_TB | \
> CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
> CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
> - CPU_FTR_PURR | CPU_FTR_REAL_LE)
> + CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)
> #define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | \
> CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
>
> @@ -375,7 +376,8 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
> #define CPU_FTRS_POSSIBLE \
> (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
> CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
> - CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT)
> + CPU_FTRS_CELL | CPU_FTRS_PA6T | CPU_FTR_1T_SEGMENT | \
> + CPU_FTR_NO_SLBIE_B)
> #else
> enum {
> CPU_FTRS_POSSIBLE =
I don't think the second hunk there is necessary, since
CPU_FTRS_POSSIBLE will already get CPU_FTR_NO_SLBIE_B via
CPU_FTRS_PA6T.
Paul.
^ permalink raw reply
* mpc 860 boot linux2.6.23 problem
From: keng_629 @ 2007-10-15 3:15 UTC (permalink / raw)
To: linuxppc-embedded@ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 303 bytes --]
i am proting linux2.63.23 to mpc860t board with uboot1.1.4 as bootloader.
my bootargs is root=/dev/ram rw init=/linuxrc.
i use debugger to see the regedits, find pc is run in the cpu_idle().
what is wrong with my kernel, plese give me some advice.thank you .
yours keng_629
keng_629
2007-10-15
[-- Attachment #2: Type: text/html, Size: 1254 bytes --]
^ permalink raw reply
* Re: [PATCH] [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
From: Michael Ellerman @ 2007-10-15 2:05 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071015014524.GG14108@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 2438 bytes --]
On Mon, 2007-10-15 at 11:45 +1000, David Gibson wrote:
> On Sun, Oct 14, 2007 at 08:01:19PM -0500, Josh Boyer wrote:
> > On Mon, 2007-10-15 at 10:54 +1000, David Gibson wrote:
> > > On Fri, Oct 12, 2007 at 06:56:24AM -0500, Josh Boyer wrote:
> > > > On Fri, 2007-10-12 at 13:30 +1000, David Gibson wrote:
> > > > > On Thu, Oct 11, 2007 at 01:42:30PM -0500, Kumar Gala wrote:
> > > > > > Move to using PAGE_OFFSET instead of TASK_SIZE or KERNELBASE value on
> > > > > > 6xx/40x/44x/fsl-booke to determine if the faulting address is a kernel or
> > > > > > user space address. This mimics how the macro is_kernel_addr()
> > > > > > works.
> > > > >
> > > > > Actually it's ambiguous whether TASK_SIZE or PAGE_OFFSET is correct in
> > > > > most of these cases (KERNELBASE is certainly wrong, though).
> > > > >
> > > > > TASK_SIZE is the top of the userspace mapped area, PAGE_OFFSET is the
> > > > > bottom of the linear mapping. So, strictly speaking there are 3 paths
> > > > > for the miss handlers: < TASK_SIZE => user mapping, >= PAGE_OFFSET =>
> > > > > kernel mapping, between the two => immediate fault.
> > > > >
> > > > > We get away with a two way comparison on 32-bit because, a) they have
> > > > > the same value and b) none of the pagetables, user or kernel, should
> > > > > have any entries in the in between region so we'll end up in
> > > > > do_page_fault in the end, anyway.
> > > >
> > > > Kumar's other patch removes the gap. He changed the default
> > > > CONFIG_TASK_SIZE to 0xc0000000.
> > >
> > > That's (a) and only removes the gap in the default configuration..
> >
> > I believe the idea was that as defconfigs get updated for 2.6.24, they
> > would pick up the new default.
>
> Yes, but if someone overrides CONFIG_TASK_SIZE, it should still work,
> yes? Or else this should not be a CONFIG option at all. Which it
> will, of course, because of (b), but one should still be aware of the
> theoretical 3-way branch when touching this code, even if it can be
> reduced to 2-way branch in practice.
There's a construct involving the characters "/" and "*" which I believe
can solve this problem.
cheers
--
Michael Ellerman
OzLabs, IBM Australia Development Lab
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
From: David Gibson @ 2007-10-15 1:45 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <1192410079.13993.4.camel@localhost.localdomain>
On Sun, Oct 14, 2007 at 08:01:19PM -0500, Josh Boyer wrote:
> On Mon, 2007-10-15 at 10:54 +1000, David Gibson wrote:
> > On Fri, Oct 12, 2007 at 06:56:24AM -0500, Josh Boyer wrote:
> > > On Fri, 2007-10-12 at 13:30 +1000, David Gibson wrote:
> > > > On Thu, Oct 11, 2007 at 01:42:30PM -0500, Kumar Gala wrote:
> > > > > Move to using PAGE_OFFSET instead of TASK_SIZE or KERNELBASE value on
> > > > > 6xx/40x/44x/fsl-booke to determine if the faulting address is a kernel or
> > > > > user space address. This mimics how the macro is_kernel_addr()
> > > > > works.
> > > >
> > > > Actually it's ambiguous whether TASK_SIZE or PAGE_OFFSET is correct in
> > > > most of these cases (KERNELBASE is certainly wrong, though).
> > > >
> > > > TASK_SIZE is the top of the userspace mapped area, PAGE_OFFSET is the
> > > > bottom of the linear mapping. So, strictly speaking there are 3 paths
> > > > for the miss handlers: < TASK_SIZE => user mapping, >= PAGE_OFFSET =>
> > > > kernel mapping, between the two => immediate fault.
> > > >
> > > > We get away with a two way comparison on 32-bit because, a) they have
> > > > the same value and b) none of the pagetables, user or kernel, should
> > > > have any entries in the in between region so we'll end up in
> > > > do_page_fault in the end, anyway.
> > >
> > > Kumar's other patch removes the gap. He changed the default
> > > CONFIG_TASK_SIZE to 0xc0000000.
> >
> > That's (a) and only removes the gap in the default configuration..
>
> I believe the idea was that as defconfigs get updated for 2.6.24, they
> would pick up the new default.
Yes, but if someone overrides CONFIG_TASK_SIZE, it should still work,
yes? Or else this should not be a CONFIG option at all. Which it
will, of course, because of (b), but one should still be aware of the
theoretical 3-way branch when touching this code, even if it can be
reduced to 2-way branch in practice.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* [PATCH] pasemi: process i2c device tree entries at boot
From: Olof Johansson @ 2007-10-15 1:52 UTC (permalink / raw)
To: paulus; +Cc: linuxppc-dev
Setup i2c_board_info based on device tree contents. This has to be
a device_initcall since we need PCI to be probed by the time we
run it, but before the actual driver is initialized.
Signed-off-by: Olof Johansson <olof@lixom.net>
Index: k.org/arch/powerpc/platforms/pasemi/Makefile
===================================================================
--- k.org.orig/arch/powerpc/platforms/pasemi/Makefile
+++ k.org/arch/powerpc/platforms/pasemi/Makefile
@@ -1,4 +1,4 @@
-obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
+obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o misc.o
obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o
obj-$(CONFIG_ELECTRA_IDE) += electra_ide.o
obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
Index: k.org/arch/powerpc/platforms/pasemi/misc.c
===================================================================
--- /dev/null
+++ k.org/arch/powerpc/platforms/pasemi/misc.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Parts based on arch/powerpc/sysdev/fsl_soc.c:
+ *
+ * 2006 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+
+#ifdef CONFIG_I2C_BOARDINFO
+/* The below is from fsl_soc.c. It's copied because since there are no
+ * official bus bindings at this time it doesn't make sense to share across
+ * the platforms, even though they happen to be common.
+ */
+struct i2c_driver_device {
+ char *of_device;
+ char *i2c_driver;
+ char *i2c_type;
+};
+
+static struct i2c_driver_device i2c_devices[] __initdata = {
+ {"dallas,ds1338", "rtc-ds1307", "ds1338"},
+};
+
+static int __init find_i2c_driver(struct device_node *node,
+ struct i2c_board_info *info)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
+ if (!of_device_is_compatible(node, i2c_devices[i].of_device))
+ continue;
+ if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
+ KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
+ strlcpy(info->type, i2c_devices[i].i2c_type,
+ I2C_NAME_SIZE) >= I2C_NAME_SIZE)
+ return -ENOMEM;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int __init pasemi_register_i2c_devices(void)
+{
+ struct pci_dev *pdev;
+ struct device_node *adap_node;
+ struct device_node *node;
+
+ pdev = NULL;
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa003, pdev))) {
+ adap_node = pci_device_to_OF_node(pdev);
+
+ node = NULL;
+ while ((node = of_get_next_child(adap_node, node))) {
+ struct i2c_board_info info = {};
+ const u32 *addr;
+ int len;
+
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || len < sizeof(int) ||
+ *addr > (1 << 10) - 1) {
+ printk(KERN_WARNING
+ "pasemi_register_i2c_devices: "
+ "invalid i2c device entry\n");
+ continue;
+ }
+
+ info.irq = irq_of_parse_and_map(node, 0);
+ if (info.irq == NO_IRQ)
+ info.irq = -1;
+
+ if (find_i2c_driver(node, &info) < 0)
+ continue;
+
+ info.addr = *addr;
+
+ i2c_register_board_info(PCI_FUNC(pdev->devfn), &info,
+ 1);
+ }
+ }
+ return 0;
+}
+device_initcall(pasemi_register_i2c_devices);
+#endif
^ permalink raw reply
* Re: [PATCH] [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
From: Josh Boyer @ 2007-10-15 1:01 UTC (permalink / raw)
To: David Gibson; +Cc: linuxppc-dev
In-Reply-To: <20071015005447.GD14108@localhost.localdomain>
On Mon, 2007-10-15 at 10:54 +1000, David Gibson wrote:
> On Fri, Oct 12, 2007 at 06:56:24AM -0500, Josh Boyer wrote:
> > On Fri, 2007-10-12 at 13:30 +1000, David Gibson wrote:
> > > On Thu, Oct 11, 2007 at 01:42:30PM -0500, Kumar Gala wrote:
> > > > Move to using PAGE_OFFSET instead of TASK_SIZE or KERNELBASE value on
> > > > 6xx/40x/44x/fsl-booke to determine if the faulting address is a kernel or
> > > > user space address. This mimics how the macro is_kernel_addr()
> > > > works.
> > >
> > > Actually it's ambiguous whether TASK_SIZE or PAGE_OFFSET is correct in
> > > most of these cases (KERNELBASE is certainly wrong, though).
> > >
> > > TASK_SIZE is the top of the userspace mapped area, PAGE_OFFSET is the
> > > bottom of the linear mapping. So, strictly speaking there are 3 paths
> > > for the miss handlers: < TASK_SIZE => user mapping, >= PAGE_OFFSET =>
> > > kernel mapping, between the two => immediate fault.
> > >
> > > We get away with a two way comparison on 32-bit because, a) they have
> > > the same value and b) none of the pagetables, user or kernel, should
> > > have any entries in the in between region so we'll end up in
> > > do_page_fault in the end, anyway.
> >
> > Kumar's other patch removes the gap. He changed the default
> > CONFIG_TASK_SIZE to 0xc0000000.
>
> That's (a) and only removes the gap in the default configuration..
I believe the idea was that as defconfigs get updated for 2.6.24, they
would pick up the new default.
josh
^ permalink raw reply
* Re: [PATCH] [POWERPC] Use PAGE_OFFSET to tell if an address is user/kernel in SW TLB handlers
From: David Gibson @ 2007-10-15 0:54 UTC (permalink / raw)
To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <1192190184.3061.27.camel@localhost.localdomain>
On Fri, Oct 12, 2007 at 06:56:24AM -0500, Josh Boyer wrote:
> On Fri, 2007-10-12 at 13:30 +1000, David Gibson wrote:
> > On Thu, Oct 11, 2007 at 01:42:30PM -0500, Kumar Gala wrote:
> > > Move to using PAGE_OFFSET instead of TASK_SIZE or KERNELBASE value on
> > > 6xx/40x/44x/fsl-booke to determine if the faulting address is a kernel or
> > > user space address. This mimics how the macro is_kernel_addr()
> > > works.
> >
> > Actually it's ambiguous whether TASK_SIZE or PAGE_OFFSET is correct in
> > most of these cases (KERNELBASE is certainly wrong, though).
> >
> > TASK_SIZE is the top of the userspace mapped area, PAGE_OFFSET is the
> > bottom of the linear mapping. So, strictly speaking there are 3 paths
> > for the miss handlers: < TASK_SIZE => user mapping, >= PAGE_OFFSET =>
> > kernel mapping, between the two => immediate fault.
> >
> > We get away with a two way comparison on 32-bit because, a) they have
> > the same value and b) none of the pagetables, user or kernel, should
> > have any entries in the in between region so we'll end up in
> > do_page_fault in the end, anyway.
>
> Kumar's other patch removes the gap. He changed the default
> CONFIG_TASK_SIZE to 0xc0000000.
That's (a) and only removes the gap in the default configuration..
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH v3 9/9] add MPC837x MDS board default device tree
From: David Gibson @ 2007-10-15 0:37 UTC (permalink / raw)
To: Li Yang; +Cc: linuxppc-dev, paulus
In-Reply-To: <1192195728-24189-10-git-send-email-leoli@freescale.com>
On Fri, Oct 12, 2007 at 09:28:48PM +0800, Li Yang wrote:
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> arch/powerpc/boot/dts/mpc8377_mds.dts | 288 ++++++++++++++++++++++++++++++
> arch/powerpc/boot/dts/mpc8378_mds.dts | 268 ++++++++++++++++++++++++++++
> arch/powerpc/boot/dts/mpc8379_mds.dts | 308 +++++++++++++++++++++++++++++++++
> 3 files changed, 864 insertions(+), 0 deletions(-)
> create mode 100644 arch/powerpc/boot/dts/mpc8377_mds.dts
> create mode 100644 arch/powerpc/boot/dts/mpc8378_mds.dts
> create mode 100644 arch/powerpc/boot/dts/mpc8379_mds.dts
>
> diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts
> b/arch/powerpc/boot/dts/mpc8377_mds.dts
[snip]
> + soc837x@e0000000 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + device_type = "soc";
> + ranges = <0 e0000000 00100000>;
> + reg = <e0000000 00000200>;
> + bus-frequency = <0>;
> +
> + wdt@200 {
> + device_type = "watchdog";
Drop this device_type.
> + compatible = "mpc83xx_wdt";
> + reg = <200 100>;
> + };
> +
> + i2c@3000 {
> + device_type = "i2c";
And this one.
> + compatible = "fsl-i2c";
> + reg = <3000 100>;
> + interrupts = <e 8>;
> + interrupt-parent = < &ipic >;
> + dfsrr;
> + };
> +
> + i2c@3100 {
> + device_type = "i2c";
And here.
> + compatible = "fsl-i2c";
> + reg = <3100 100>;
> + interrupts = <f 8>;
> + interrupt-parent = < &ipic >;
> + dfsrr;
> + };
> +
> + spi@7000 {
> + device_type = "spi";
And this one.
[snip]
> + crypto@30000 {
> + device_type = "crypto";
And definitely this one.
> + model = "SEC3";
> + compatible = "talitos";
> + reg = <30000 10000>;
> + interrupts = <b 8>;
> + interrupt-parent = < &ipic >;
> + /* Rev. 3.0 geometry */
> + num-channels = <4>;
> + channel-fifo-len = <18>;
> + exec-units-mask = <000009fe>;
> + descriptor-types-mask = <03ab0ebf>;
> + };
> +
> + sdhc@2e000 {
> + model = "eSDHC";
> + compatible = "fsl,esdhc";
> + reg = <2e000 1000>;
> + interrupts = <2a 8>;
> + interrupt-parent = < &ipic >;
> + };
> +
> + sata@18000 {
> + device_type = "sata";
And again.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [PATCH] Hook compat_sys_nanosleep up to high res timer code
From: Anton Blanchard @ 2007-10-14 23:16 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, mingo, tglx, linux-kernel
In-Reply-To: <200710150028.06493.arnd@arndb.de>
Hi Arnd,
> The code looks correct, but I think it would be nicer to change
> hrtimer_nanosleep to take a kernel pointer and have all three
> callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep)
> do the copy_to_user/put_compat_timespec in the caller.
Good idea, I had considered that but thought a larger cleanup might run
afoul of the merge rules :)
Regardless, here it is. Id appreciate a once over since it does affect
more code than the previous patch :)
Anton
--
Now we have high res timers on ppc64 I thought Id test them. It turns
out compat_sys_nanosleep hasnt been converted to the hrtimer code and so
is limited to HZ resolution.
The following patch pulls the copy_to_user out of hrtimer_nanosleep and
into the callers (common_nsleep, sys_nanosleep and compat_sys_nanosleep)
thus avoiding any set_fs(KERNEL_DS) or compat_alloc_userspace tricks.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 540799b..7a9398e 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -300,7 +300,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
/* Precise sleep: */
extern long hrtimer_nanosleep(struct timespec *rqtp,
- struct timespec __user *rmtp,
+ struct timespec *rmtp,
const enum hrtimer_mode mode,
const clockid_t clockid);
extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
diff --git a/kernel/compat.c b/kernel/compat.c
index 3bae374..44abfce 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -40,62 +40,26 @@ int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user
__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
}
-static long compat_nanosleep_restart(struct restart_block *restart)
-{
- unsigned long expire = restart->arg0, now = jiffies;
- struct compat_timespec __user *rmtp;
-
- /* Did it expire while we handled signals? */
- if (!time_after(expire, now))
- return 0;
-
- expire = schedule_timeout_interruptible(expire - now);
- if (expire == 0)
- return 0;
-
- rmtp = (struct compat_timespec __user *)restart->arg1;
- if (rmtp) {
- struct compat_timespec ct;
- struct timespec t;
-
- jiffies_to_timespec(expire, &t);
- ct.tv_sec = t.tv_sec;
- ct.tv_nsec = t.tv_nsec;
- if (copy_to_user(rmtp, &ct, sizeof(ct)))
- return -EFAULT;
- }
- /* The 'restart' block is already filled in */
- return -ERESTART_RESTARTBLOCK;
-}
-
asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
- struct compat_timespec __user *rmtp)
+ struct compat_timespec __user *rmtp)
{
- struct timespec t;
- struct restart_block *restart;
- unsigned long expire;
+ struct timespec tu, rmt;
+ long ret;
- if (get_compat_timespec(&t, rqtp))
+ if (get_compat_timespec(&tu, rqtp))
return -EFAULT;
- if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
+ if (!timespec_valid(&tu))
return -EINVAL;
- expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
- expire = schedule_timeout_interruptible(expire);
- if (expire == 0)
- return 0;
+ ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
- if (rmtp) {
- jiffies_to_timespec(expire, &t);
- if (put_compat_timespec(&t, rmtp))
+ if (ret) {
+ if (put_compat_timespec(&rmt, rmtp))
return -EFAULT;
}
- restart = ¤t_thread_info()->restart_block;
- restart->fn = compat_nanosleep_restart;
- restart->arg0 = jiffies + expire;
- restart->arg1 = (unsigned long) rmtp;
- return -ERESTART_RESTARTBLOCK;
+
+ return ret;
}
static inline long get_compat_itimerval(struct itimerval *o,
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index dc8a445..095e09e 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1286,8 +1286,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{
struct hrtimer_sleeper t;
- struct timespec __user *rmtp;
- struct timespec tu;
+ struct timespec *rmtp;
ktime_t time;
restart->fn = do_no_restart_syscall;
@@ -1298,14 +1297,12 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
return 0;
- rmtp = (struct timespec __user *) restart->arg1;
+ rmtp = (struct timespec *)restart->arg1;
if (rmtp) {
time = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (time.tv64 <= 0)
return 0;
- tu = ktime_to_timespec(time);
- if (copy_to_user(rmtp, &tu, sizeof(tu)))
- return -EFAULT;
+ *rmtp = ktime_to_timespec(time);
}
restart->fn = hrtimer_nanosleep_restart;
@@ -1314,12 +1311,11 @@ long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
return -ERESTART_RESTARTBLOCK;
}
-long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
+long hrtimer_nanosleep(struct timespec *rqtp, struct timespec *rmtp,
const enum hrtimer_mode mode, const clockid_t clockid)
{
struct restart_block *restart;
struct hrtimer_sleeper t;
- struct timespec tu;
ktime_t rem;
hrtimer_init(&t.timer, clockid, mode);
@@ -1335,9 +1331,7 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
rem = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (rem.tv64 <= 0)
return 0;
- tu = ktime_to_timespec(rem);
- if (copy_to_user(rmtp, &tu, sizeof(tu)))
- return -EFAULT;
+ *rmtp = ktime_to_timespec(rem);
}
restart = ¤t_thread_info()->restart_block;
@@ -1353,7 +1347,8 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
asmlinkage long
sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
{
- struct timespec tu;
+ struct timespec tu, rmt;
+ int ret;
if (copy_from_user(&tu, rqtp, sizeof(tu)))
return -EFAULT;
@@ -1361,7 +1356,14 @@ sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
if (!timespec_valid(&tu))
return -EINVAL;
- return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+ ret = hrtimer_nanosleep(&tu, &rmt, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+
+ if (ret) {
+ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+ return -EFAULT;
+ }
+
+ return ret;
}
/*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 7a15afb..fc7dac2 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -980,9 +980,19 @@ sys_clock_getres(const clockid_t which_clock, struct timespec __user *tp)
static int common_nsleep(const clockid_t which_clock, int flags,
struct timespec *tsave, struct timespec __user *rmtp)
{
- return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ?
+ struct timespec rmt;
+ int ret;
+
+ ret = hrtimer_nanosleep(tsave, &rmt, flags & TIMER_ABSTIME ?
HRTIMER_MODE_ABS : HRTIMER_MODE_REL,
which_clock);
+
+ if (ret) {
+ if (copy_to_user(rmtp, &rmt, sizeof(*rmtp)))
+ return -EFAULT;
+ }
+
+ return ret;
}
asmlinkage long
^ permalink raw reply related
* [PATCH v4] bestcomm: core bestcomm support for Freescale MPC5200
From: Grant Likely @ 2007-10-14 23:02 UTC (permalink / raw)
To: galak, paulus, linuxppc-dev, tnt, domen.puncer
From: Sylvain Munaut <tnt@246tNt.com>
Repost of the core bestcomm support patch. v3 was missing the Makefile
regression fix.
This patch adds support for the core of the BestComm API
for the Freescale MPC5200(b). The BestComm engine is a
microcode-controlled / tasks-based DMA used by several
of the onchip devices.
Setting up the tasks / memory allocation and all common
low level functions are handled by this patch.
The specifics details of each tasks and their microcode
are split-out in separate patches.
This is not the official API, but a much cleaner one.
(hopefully)
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
arch/powerpc/platforms/Kconfig | 2
arch/powerpc/sysdev/Makefile | 1
arch/powerpc/sysdev/bestcomm/Kconfig | 18 +
arch/powerpc/sysdev/bestcomm/Makefile | 8
arch/powerpc/sysdev/bestcomm/bestcomm.c | 528 ++++++++++++++++++++++++++
arch/powerpc/sysdev/bestcomm/bestcomm.h | 190 +++++++++
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h | 334 ++++++++++++++++
arch/powerpc/sysdev/bestcomm/sram.c | 177 +++++++++
arch/powerpc/sysdev/bestcomm/sram.h | 54 +++
9 files changed, 1312 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 3724cb4..bdced1e 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -315,4 +315,6 @@ config FSL_ULI1575
config CPM
bool
+source "arch/powerpc/sysdev/bestcomm/Kconfig"
+
endmenu
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1a6f564..99a77d7 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
+obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
mv64x60_udbg.o
diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
new file mode 100644
index 0000000..3366e24
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Kconfig
@@ -0,0 +1,18 @@
+#
+# Kconfig options for Bestcomm
+#
+
+config PPC_BESTCOMM
+ tristate "Bestcomm DMA engine support"
+ depends on PPC_MPC52xx
+ default n
+ select PPC_LIB_RHEAP
+ help
+ BestComm is the name of the communication coprocessor found
+ on the Freescale MPC5200 family of processor. It's usage is
+ optionnal for some drivers (like ATA), but required for
+ others (like FEC).
+
+ If you want to use drivers that require DMA operations,
+ answer Y or M. Otherwise say N.
+
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
new file mode 100644
index 0000000..a24aa06
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for BestComm & co
+#
+
+bestcomm-core-objs := bestcomm.o sram.o
+
+obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o
+
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
new file mode 100644
index 0000000..48492a8
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
@@ -0,0 +1,528 @@
+/*
+ * Driver for MPC52xx processor BestComm peripheral controller
+ *
+ *
+ * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005 Varma Electronics Oy,
+ * ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ * ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpc52xx.h>
+
+#include "sram.h"
+#include "bestcomm_priv.h"
+#include "bestcomm.h"
+
+#define DRIVER_NAME "bestcomm-core"
+
+
+struct bcom_engine *bcom_eng = NULL;
+EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */
+
+
+/* ======================================================================== */
+/* Public and private API */
+/* ======================================================================== */
+
+/* Private API */
+
+struct bcom_task *
+bcom_task_alloc(int bd_count, int bd_size, int priv_size)
+{
+ int i, tasknum = -1;
+ struct bcom_task *tsk;
+
+ /* Get and reserve a task num */
+ spin_lock(&bcom_eng->lock);
+
+ for (i=0; i<BCOM_MAX_TASKS; i++)
+ if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */
+ bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */
+ tasknum = i;
+ break;
+ }
+
+ spin_unlock(&bcom_eng->lock);
+
+ if (tasknum < 0)
+ return NULL;
+
+ /* Allocate our structure */
+ tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
+ if (!tsk)
+ goto error;
+
+ tsk->tasknum = tasknum;
+ if (priv_size)
+ tsk->priv = (void*)tsk + sizeof(struct bcom_task);
+
+ /* Get IRQ of that task */
+ tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
+ if (tsk->irq == NO_IRQ)
+ goto error;
+
+ /* Init the BDs, if needed */
+ if (bd_count) {
+ tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL);
+ if (!tsk->cookie)
+ goto error;
+
+ tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
+ if (!tsk->bd)
+ goto error;
+ memset(tsk->bd, 0x00, bd_count * bd_size);
+
+ tsk->num_bd = bd_count;
+ tsk->bd_size = bd_size;
+ }
+
+ return tsk;
+
+error:
+ if (tsk) {
+ if (tsk->irq != NO_IRQ)
+ irq_dispose_mapping(tsk->irq);
+ bcom_sram_free(tsk->bd);
+ kfree(tsk->cookie);
+ kfree(tsk);
+ }
+
+ bcom_eng->tdt[tasknum].stop = 0;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(bcom_task_alloc);
+
+void
+bcom_task_free(struct bcom_task *tsk)
+{
+ /* Stop the task */
+ bcom_disable_task(tsk->tasknum);
+
+ /* Clear TDT */
+ bcom_eng->tdt[tsk->tasknum].start = 0;
+ bcom_eng->tdt[tsk->tasknum].stop = 0;
+
+ /* Free everything */
+ irq_dispose_mapping(tsk->irq);
+ bcom_sram_free(tsk->bd);
+ kfree(tsk->cookie);
+ kfree(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_task_free);
+
+int
+bcom_load_image(int task, u32 *task_image)
+{
+ struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
+ struct bcom_tdt *tdt;
+ u32 *desc, *var, *inc;
+ u32 *desc_src, *var_src, *inc_src;
+
+ /* Safety checks */
+ if (hdr->magic != BCOM_TASK_MAGIC) {
+ printk(KERN_ERR DRIVER_NAME
+ ": Trying to load invalid microcode\n");
+ return -EINVAL;
+ }
+
+ if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
+ printk(KERN_ERR DRIVER_NAME
+ ": Trying to load invalid task %d\n", task);
+ return -EINVAL;
+ }
+
+ /* Initial load or reload */
+ tdt = &bcom_eng->tdt[task];
+
+ if (tdt->start) {
+ desc = bcom_task_desc(task);
+ if (hdr->desc_size != bcom_task_num_descs(task)) {
+ printk(KERN_ERR DRIVER_NAME
+ ": Trying to reload wrong task image "
+ "(%d size %d/%d)!\n",
+ task,
+ hdr->desc_size,
+ bcom_task_num_descs(task));
+ return -EINVAL;
+ }
+ } else {
+ phys_addr_t start_pa;
+
+ desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
+ if (!desc)
+ return -ENOMEM;
+
+ tdt->start = start_pa;
+ tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
+ }
+
+ var = bcom_task_var(task);
+ inc = bcom_task_inc(task);
+
+ /* Clear & copy */
+ memset(var, 0x00, BCOM_VAR_SIZE);
+ memset(inc, 0x00, BCOM_INC_SIZE);
+
+ desc_src = (u32 *)(hdr + 1);
+ var_src = desc_src + hdr->desc_size;
+ inc_src = var_src + hdr->var_size;
+
+ memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
+ memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
+ memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_load_image);
+
+void
+bcom_set_initiator(int task, int initiator)
+{
+ int i;
+ int num_descs;
+ u32 *desc;
+ int next_drd_has_initiator;
+
+ bcom_set_tcr_initiator(task, initiator);
+
+ /* Just setting tcr is apparently not enough due to some problem */
+ /* with it. So we just go thru all the microcode and replace in */
+ /* the DRD directly */
+
+ desc = bcom_task_desc(task);
+ next_drd_has_initiator = 1;
+ num_descs = bcom_task_num_descs(task);
+
+ for (i=0; i<num_descs; i++, desc++) {
+ if (!bcom_desc_is_drd(*desc))
+ continue;
+ if (next_drd_has_initiator)
+ if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
+ bcom_set_desc_initiator(desc, initiator);
+ next_drd_has_initiator = !bcom_drd_is_extended(*desc);
+ }
+}
+EXPORT_SYMBOL_GPL(bcom_set_initiator);
+
+
+/* Public API */
+
+void
+bcom_enable(struct bcom_task *tsk)
+{
+ bcom_enable_task(tsk->tasknum);
+}
+EXPORT_SYMBOL_GPL(bcom_enable);
+
+void
+bcom_disable(struct bcom_task *tsk)
+{
+ bcom_disable_task(tsk->tasknum);
+}
+EXPORT_SYMBOL_GPL(bcom_disable);
+
+
+/* ======================================================================== */
+/* Engine init/cleanup */
+/* ======================================================================== */
+
+/* Function Descriptor table */
+/* this will need to be updated if Freescale changes their task code FDT */
+static u32 fdt_ops[] = {
+ 0xa0045670, /* FDT[48] - load_acc() */
+ 0x80045670, /* FDT[49] - unload_acc() */
+ 0x21800000, /* FDT[50] - and() */
+ 0x21e00000, /* FDT[51] - or() */
+ 0x21500000, /* FDT[52] - xor() */
+ 0x21400000, /* FDT[53] - andn() */
+ 0x21500000, /* FDT[54] - not() */
+ 0x20400000, /* FDT[55] - add() */
+ 0x20500000, /* FDT[56] - sub() */
+ 0x20800000, /* FDT[57] - lsh() */
+ 0x20a00000, /* FDT[58] - rsh() */
+ 0xc0170000, /* FDT[59] - crc8() */
+ 0xc0145670, /* FDT[60] - crc16() */
+ 0xc0345670, /* FDT[61] - crc32() */
+ 0xa0076540, /* FDT[62] - endian32() */
+ 0xa0000760, /* FDT[63] - endian16() */
+};
+
+
+static int __devinit
+bcom_engine_init(void)
+{
+ int task;
+ phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
+ unsigned int tdt_size, ctx_size, var_size, fdt_size;
+
+ /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
+ tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
+ ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
+ var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
+ fdt_size = BCOM_FDT_SIZE;
+
+ bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
+ bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
+ bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
+ bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
+
+ if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
+ printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
+
+ bcom_sram_free(bcom_eng->tdt);
+ bcom_sram_free(bcom_eng->ctx);
+ bcom_sram_free(bcom_eng->var);
+ bcom_sram_free(bcom_eng->fdt);
+
+ return -ENOMEM;
+ }
+
+ memset(bcom_eng->tdt, 0x00, tdt_size);
+ memset(bcom_eng->ctx, 0x00, ctx_size);
+ memset(bcom_eng->var, 0x00, var_size);
+ memset(bcom_eng->fdt, 0x00, fdt_size);
+
+ /* Copy the FDT for the EU#3 */
+ memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
+
+ /* Initialize Task base structure */
+ for (task=0; task<BCOM_MAX_TASKS; task++)
+ {
+ out_be16(&bcom_eng->regs->tcr[task], 0);
+ out_8(&bcom_eng->regs->ipr[task], 0);
+
+ bcom_eng->tdt[task].context = ctx_pa;
+ bcom_eng->tdt[task].var = var_pa;
+ bcom_eng->tdt[task].fdt = fdt_pa;
+
+ var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
+ ctx_pa += BCOM_CTX_SIZE;
+ }
+
+ out_be32(&bcom_eng->regs->taskBar, tdt_pa);
+
+ /* Init 'always' initiator */
+ out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
+
+ /* Disable COMM Bus Prefetch, apparently it's not reliable yet */
+ /* FIXME: This should be done on 5200 and not 5200B ... */
+ out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1);
+
+ /* Init lock */
+ spin_lock_init(&bcom_eng->lock);
+
+ return 0;
+}
+
+static void
+bcom_engine_cleanup(void)
+{
+ int task;
+
+ /* Stop all tasks */
+ for (task=0; task<BCOM_MAX_TASKS; task++)
+ {
+ out_be16(&bcom_eng->regs->tcr[task], 0);
+ out_8(&bcom_eng->regs->ipr[task], 0);
+ }
+
+ out_be32(&bcom_eng->regs->taskBar, 0ul);
+
+ /* Release the SRAM zones */
+ bcom_sram_free(bcom_eng->tdt);
+ bcom_sram_free(bcom_eng->ctx);
+ bcom_sram_free(bcom_eng->var);
+ bcom_sram_free(bcom_eng->fdt);
+}
+
+
+/* ======================================================================== */
+/* OF platform driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *ofn_sram;
+ struct resource res_bcom;
+
+ int rv;
+
+ /* Inform user we're ok so far */
+ printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
+
+ /* Get the bestcomm node */
+ of_node_get(op->node);
+
+ /* Prepare SRAM */
+ ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram");
+ if (!ofn_sram) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "No SRAM found in device tree\n");
+ rv = -ENODEV;
+ goto error_ofput;
+ }
+ rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
+ of_node_put(ofn_sram);
+
+ if (rv) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Error in SRAM init\n");
+ goto error_ofput;
+ }
+
+ /* Get a clean struct */
+ bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
+ if (!bcom_eng) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Can't allocate state structure\n");
+ rv = -ENOMEM;
+ goto error_sramclean;
+ }
+
+ /* Save the node */
+ bcom_eng->ofnode = op->node;
+
+ /* Get, reserve & map io */
+ if (of_address_to_resource(op->node, 0, &res_bcom)) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Can't get resource\n");
+ rv = -EINVAL;
+ goto error_sramclean;
+ }
+
+ if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
+ DRIVER_NAME)) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Can't request registers region\n");
+ rv = -EBUSY;
+ goto error_sramclean;
+ }
+
+ bcom_eng->regs_base = res_bcom.start;
+ bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
+ if (!bcom_eng->regs) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Can't map registers\n");
+ rv = -ENOMEM;
+ goto error_release;
+ }
+
+ /* Now, do the real init */
+ rv = bcom_engine_init();
+ if (rv)
+ goto error_unmap;
+
+ /* Done ! */
+ printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
+ bcom_eng->regs_base);
+
+ return 0;
+
+ /* Error path */
+error_unmap:
+ iounmap(bcom_eng->regs);
+error_release:
+ release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
+error_sramclean:
+ kfree(bcom_eng);
+ bcom_sram_cleanup();
+error_ofput:
+ of_node_put(op->node);
+
+ printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
+
+ return rv;
+}
+
+
+static int
+mpc52xx_bcom_remove(struct of_device *op)
+{
+ /* Clean up the engine */
+ bcom_engine_cleanup();
+
+ /* Cleanup SRAM */
+ bcom_sram_cleanup();
+
+ /* Release regs */
+ iounmap(bcom_eng->regs);
+ release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
+
+ /* Release the node */
+ of_node_put(bcom_eng->ofnode);
+
+ /* Release memory */
+ kfree(bcom_eng);
+ bcom_eng = NULL;
+
+ return 0;
+}
+
+static struct of_device_id mpc52xx_bcom_of_match[] = {
+ {
+ .type = "dma-controller",
+ .compatible = "mpc5200-bestcomm",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
+
+
+static struct of_platform_driver mpc52xx_bcom_of_platform_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = mpc52xx_bcom_of_match,
+ .probe = mpc52xx_bcom_probe,
+ .remove = mpc52xx_bcom_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_bcom_init(void)
+{
+ return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver);
+}
+
+static void __exit
+mpc52xx_bcom_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver);
+}
+
+/* If we're not a module, we must make sure everything is setup before */
+/* anyone tries to use us ... that's why we use subsys_initcall instead */
+/* of module_init. */
+subsys_initcall(mpc52xx_bcom_init);
+module_exit(mpc52xx_bcom_exit);
+
+MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
+MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
new file mode 100644
index 0000000..e802cb4
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
@@ -0,0 +1,190 @@
+/*
+ * Public header for the MPC52xx processor BestComm driver
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005 Varma Electronics Oy,
+ * ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ * ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_H__
+#define __BESTCOMM_H__
+
+struct bcom_bd; /* defined later on ... */
+
+
+/* ======================================================================== */
+/* Generic task managment */
+/* ======================================================================== */
+
+/**
+ * struct bcom_task - Structure describing a loaded BestComm task
+ *
+ * This structure is never built by the driver it self. It's built and
+ * filled the intermediate layer of the BestComm API, the task dependent
+ * support code.
+ *
+ * Most likely you don't need to poke around inside this structure. The
+ * fields are exposed in the header just for the sake of inline functions
+ */
+struct bcom_task {
+ unsigned int tasknum;
+ unsigned int flags;
+ int irq;
+
+ struct bcom_bd *bd;
+ phys_addr_t bd_pa;
+ void **cookie;
+ unsigned short index;
+ unsigned short outdex;
+ unsigned int num_bd;
+ unsigned int bd_size;
+
+ void* priv;
+};
+
+#define BCOM_FLAGS_NONE 0x00000000ul
+#define BCOM_FLAGS_ENABLE_TASK (1ul << 0)
+
+/**
+ * bcom_enable - Enable a BestComm task
+ * @tsk: The BestComm task structure
+ *
+ * This function makes sure the given task is enabled and can be run
+ * by the BestComm engine as needed
+ */
+extern void bcom_enable(struct bcom_task *tsk);
+
+/**
+ * bcom_disable - Disable a BestComm task
+ * @tsk: The BestComm task structure
+ *
+ * This function disable a given task, making sure it's not executed
+ * by the BestComm engine.
+ */
+extern void bcom_disable(struct bcom_task *tsk);
+
+
+/**
+ * bcom_get_task_irq - Returns the irq number of a BestComm task
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_get_task_irq(struct bcom_task *tsk) {
+ return tsk->irq;
+}
+
+/* ======================================================================== */
+/* BD based tasks helpers */
+/* ======================================================================== */
+
+/**
+ * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
+ * @status: The current status of this buffer. Exact meaning depends on the
+ * task type
+ * @data: An array of u32 whose meaning depends on the task type.
+ */
+struct bcom_bd {
+ u32 status;
+ u32 data[1]; /* variable, but at least 1 */
+};
+
+#define BCOM_BD_READY 0x40000000ul
+
+/** _bcom_next_index - Get next input index.
+ * @tsk: pointer to task structure
+ *
+ * Support function; Device drivers should not call this
+ */
+static inline int
+_bcom_next_index(struct bcom_task *tsk)
+{
+ return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1;
+}
+
+/** _bcom_next_outdex - Get next output index.
+ * @tsk: pointer to task structure
+ *
+ * Support function; Device drivers should not call this
+ */
+static inline int
+_bcom_next_outdex(struct bcom_task *tsk)
+{
+ return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1;
+}
+
+/**
+ * bcom_queue_empty - Checks if a BestComm task BD queue is empty
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_queue_empty(struct bcom_task *tsk)
+{
+ return tsk->index == tsk->outdex;
+}
+
+/**
+ * bcom_queue_full - Checks if a BestComm task BD queue is full
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_queue_full(struct bcom_task *tsk)
+{
+ return tsk->outdex == _bcom_next_index(tsk);
+}
+
+/**
+ * bcom_buffer_done - Checks if a BestComm
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_buffer_done(struct bcom_task *tsk)
+{
+ if (bcom_queue_empty(tsk))
+ return 0;
+ return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
+}
+
+/**
+ * bcom_prepare_next_buffer - clear status of next available buffer.
+ * @tsk: The BestComm task structure
+ *
+ * Returns pointer to next buffer descriptor
+ */
+static inline struct bcom_bd *
+bcom_prepare_next_buffer(struct bcom_task *tsk)
+{
+ tsk->bd[tsk->index].status = 0; /* cleanup last status */
+ return &tsk->bd[tsk->index];
+}
+
+static inline void
+bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
+{
+ tsk->cookie[tsk->index] = cookie;
+ mb(); /* ensure the bd is really up-to-date */
+ tsk->bd[tsk->index].status |= BCOM_BD_READY;
+ tsk->index = _bcom_next_index(tsk);
+ if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
+ bcom_enable(tsk);
+}
+
+static inline void *
+bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
+{
+ void *cookie = tsk->cookie[tsk->outdex];
+ if (p_status)
+ *p_status = tsk->bd[tsk->outdex].status;
+ if (p_bd)
+ *p_bd = &tsk->bd[tsk->outdex];
+ tsk->outdex = _bcom_next_outdex(tsk);
+ return cookie;
+}
+
+#endif /* __BESTCOMM_H__ */
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
new file mode 100644
index 0000000..866a291
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
@@ -0,0 +1,334 @@
+/*
+ * Private header for the MPC52xx processor BestComm driver
+ *
+ * By private, we mean that driver should not use it directly. It's meant
+ * to be used by the BestComm engine driver itself and by the intermediate
+ * layer between the core and the drivers.
+ *
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005 Varma Electronics Oy,
+ * ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ * ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_PRIV_H__
+#define __BESTCOMM_PRIV_H__
+
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+
+#include "sram.h"
+
+
+/* ======================================================================== */
+/* Engine related stuff */
+/* ======================================================================== */
+
+/* Zones sizes and needed alignments */
+#define BCOM_MAX_TASKS 16
+#define BCOM_MAX_VAR 24
+#define BCOM_MAX_INC 8
+#define BCOM_MAX_FDT 64
+#define BCOM_MAX_CTX 20
+#define BCOM_CTX_SIZE (BCOM_MAX_CTX * sizeof(u32))
+#define BCOM_CTX_ALIGN 0x100
+#define BCOM_VAR_SIZE (BCOM_MAX_VAR * sizeof(u32))
+#define BCOM_INC_SIZE (BCOM_MAX_INC * sizeof(u32))
+#define BCOM_VAR_ALIGN 0x80
+#define BCOM_FDT_SIZE (BCOM_MAX_FDT * sizeof(u32))
+#define BCOM_FDT_ALIGN 0x100
+
+/**
+ * struct bcom_tdt - Task Descriptor Table Entry
+ *
+ */
+struct bcom_tdt {
+ u32 start;
+ u32 stop;
+ u32 var;
+ u32 fdt;
+ u32 exec_status; /* used internally by BestComm engine */
+ u32 mvtp; /* used internally by BestComm engine */
+ u32 context;
+ u32 litbase;
+};
+
+/**
+ * struct bcom_engine
+ *
+ * This holds all info needed globaly to handle the engine
+ */
+struct bcom_engine {
+ struct device_node *ofnode;
+ struct mpc52xx_sdma __iomem *regs;
+ phys_addr_t regs_base;
+
+ struct bcom_tdt *tdt;
+ u32 *ctx;
+ u32 *var;
+ u32 *fdt;
+
+ spinlock_t lock;
+};
+
+extern struct bcom_engine *bcom_eng;
+
+
+/* ======================================================================== */
+/* Tasks related stuff */
+/* ======================================================================== */
+
+/* Tasks image header */
+#define BCOM_TASK_MAGIC 0x4243544B /* 'BCTK' */
+
+struct bcom_task_header {
+ u32 magic;
+ u8 desc_size; /* the size fields */
+ u8 var_size; /* are given in number */
+ u8 inc_size; /* of 32-bits words */
+ u8 first_var;
+ u8 reserved[8];
+};
+
+/* Descriptors stucture & co */
+#define BCOM_DESC_NOP 0x000001f8
+#define BCOM_LCD_MASK 0x80000000
+#define BCOM_DRD_EXTENDED 0x40000000
+#define BCOM_DRD_INITIATOR_SHIFT 21
+
+/* Tasks pragma */
+#define BCOM_PRAGMA_BIT_RSV 7 /* reserved pragma bit */
+#define BCOM_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */
+ /* 1=iter end */
+#define BCOM_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */
+ /* task enable */
+#define BCOM_PRAGMA_BIT_PACK 4 /* pack data enable */
+#define BCOM_PRAGMA_BIT_INTEGER 3 /* data alignment */
+ /* 0=frac(msb), 1=int(lsb) */
+#define BCOM_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */
+#define BCOM_PRAGMA_BIT_CW 1 /* write line buffer enable */
+#define BCOM_PRAGMA_BIT_RL 0 /* read line buffer enable */
+
+ /* Looks like XLB speculative read generates XLB errors when a buffer
+ * is at the end of the physical memory. i.e. when accessing the
+ * lasts words, the engine tries to prefetch the next but there is no
+ * next ...
+ */
+#define BCOM_STD_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \
+ (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \
+ (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \
+ (0 << BCOM_PRAGMA_BIT_PACK) | \
+ (0 << BCOM_PRAGMA_BIT_INTEGER) | \
+ (0 << BCOM_PRAGMA_BIT_SPECREAD) | \
+ (1 << BCOM_PRAGMA_BIT_CW) | \
+ (1 << BCOM_PRAGMA_BIT_RL))
+
+#define BCOM_PCI_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \
+ (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \
+ (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \
+ (0 << BCOM_PRAGMA_BIT_PACK) | \
+ (1 << BCOM_PRAGMA_BIT_INTEGER) | \
+ (0 << BCOM_PRAGMA_BIT_SPECREAD) | \
+ (1 << BCOM_PRAGMA_BIT_CW) | \
+ (1 << BCOM_PRAGMA_BIT_RL))
+
+#define BCOM_ATA_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_CRC16_DP_0_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_CRC16_DP_1_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_FEC_RX_BD_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_FEC_TX_BD_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_0_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_1_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_2_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_3_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_BD_0_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_BD_1_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_RX_BD_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_TX_BD_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_GEN_LPC_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_PCI_RX_PRAGMA BCOM_PCI_PRAGMA
+#define BCOM_PCI_TX_PRAGMA BCOM_PCI_PRAGMA
+
+/* Initiators number */
+#define BCOM_INITIATOR_ALWAYS 0
+#define BCOM_INITIATOR_SCTMR_0 1
+#define BCOM_INITIATOR_SCTMR_1 2
+#define BCOM_INITIATOR_FEC_RX 3
+#define BCOM_INITIATOR_FEC_TX 4
+#define BCOM_INITIATOR_ATA_RX 5
+#define BCOM_INITIATOR_ATA_TX 6
+#define BCOM_INITIATOR_SCPCI_RX 7
+#define BCOM_INITIATOR_SCPCI_TX 8
+#define BCOM_INITIATOR_PSC3_RX 9
+#define BCOM_INITIATOR_PSC3_TX 10
+#define BCOM_INITIATOR_PSC2_RX 11
+#define BCOM_INITIATOR_PSC2_TX 12
+#define BCOM_INITIATOR_PSC1_RX 13
+#define BCOM_INITIATOR_PSC1_TX 14
+#define BCOM_INITIATOR_SCTMR_2 15
+#define BCOM_INITIATOR_SCLPC 16
+#define BCOM_INITIATOR_PSC5_RX 17
+#define BCOM_INITIATOR_PSC5_TX 18
+#define BCOM_INITIATOR_PSC4_RX 19
+#define BCOM_INITIATOR_PSC4_TX 20
+#define BCOM_INITIATOR_I2C2_RX 21
+#define BCOM_INITIATOR_I2C2_TX 22
+#define BCOM_INITIATOR_I2C1_RX 23
+#define BCOM_INITIATOR_I2C1_TX 24
+#define BCOM_INITIATOR_PSC6_RX 25
+#define BCOM_INITIATOR_PSC6_TX 26
+#define BCOM_INITIATOR_IRDA_RX 25
+#define BCOM_INITIATOR_IRDA_TX 26
+#define BCOM_INITIATOR_SCTMR_3 27
+#define BCOM_INITIATOR_SCTMR_4 28
+#define BCOM_INITIATOR_SCTMR_5 29
+#define BCOM_INITIATOR_SCTMR_6 30
+#define BCOM_INITIATOR_SCTMR_7 31
+
+/* Initiators priorities */
+#define BCOM_IPR_ALWAYS 7
+#define BCOM_IPR_SCTMR_0 2
+#define BCOM_IPR_SCTMR_1 2
+#define BCOM_IPR_FEC_RX 6
+#define BCOM_IPR_FEC_TX 5
+#define BCOM_IPR_ATA_RX 4
+#define BCOM_IPR_ATA_TX 3
+#define BCOM_IPR_SCPCI_RX 2
+#define BCOM_IPR_SCPCI_TX 2
+#define BCOM_IPR_PSC3_RX 2
+#define BCOM_IPR_PSC3_TX 2
+#define BCOM_IPR_PSC2_RX 2
+#define BCOM_IPR_PSC2_TX 2
+#define BCOM_IPR_PSC1_RX 2
+#define BCOM_IPR_PSC1_TX 2
+#define BCOM_IPR_SCTMR_2 2
+#define BCOM_IPR_SCLPC 2
+#define BCOM_IPR_PSC5_RX 2
+#define BCOM_IPR_PSC5_TX 2
+#define BCOM_IPR_PSC4_RX 2
+#define BCOM_IPR_PSC4_TX 2
+#define BCOM_IPR_I2C2_RX 2
+#define BCOM_IPR_I2C2_TX 2
+#define BCOM_IPR_I2C1_RX 2
+#define BCOM_IPR_I2C1_TX 2
+#define BCOM_IPR_PSC6_RX 2
+#define BCOM_IPR_PSC6_TX 2
+#define BCOM_IPR_IRDA_RX 2
+#define BCOM_IPR_IRDA_TX 2
+#define BCOM_IPR_SCTMR_3 2
+#define BCOM_IPR_SCTMR_4 2
+#define BCOM_IPR_SCTMR_5 2
+#define BCOM_IPR_SCTMR_6 2
+#define BCOM_IPR_SCTMR_7 2
+
+
+/* ======================================================================== */
+/* API */
+/* ======================================================================== */
+
+extern struct bcom_task *bcom_task_alloc(int bd_count, int bd_size, int priv_size);
+extern void bcom_task_free(struct bcom_task *tsk);
+extern int bcom_load_image(int task, u32 *task_image);
+extern void bcom_set_initiator(int task, int initiator);
+
+
+#define TASK_ENABLE 0x8000
+
+static inline void
+bcom_enable_task(int task)
+{
+ u16 reg;
+ reg = in_be16(&bcom_eng->regs->tcr[task]);
+ out_be16(&bcom_eng->regs->tcr[task], reg | TASK_ENABLE);
+}
+
+static inline void
+bcom_disable_task(int task)
+{
+ u16 reg = in_be16(&bcom_eng->regs->tcr[task]);
+ out_be16(&bcom_eng->regs->tcr[task], reg & ~TASK_ENABLE);
+}
+
+
+static inline u32 *
+bcom_task_desc(int task)
+{
+ return bcom_sram_pa2va(bcom_eng->tdt[task].start);
+}
+
+static inline int
+bcom_task_num_descs(int task)
+{
+ return (bcom_eng->tdt[task].stop - bcom_eng->tdt[task].start)/sizeof(u32) + 1;
+}
+
+static inline u32 *
+bcom_task_var(int task)
+{
+ return bcom_sram_pa2va(bcom_eng->tdt[task].var);
+}
+
+static inline u32 *
+bcom_task_inc(int task)
+{
+ return &bcom_task_var(task)[BCOM_MAX_VAR];
+}
+
+
+static inline int
+bcom_drd_is_extended(u32 desc)
+{
+ return (desc) & BCOM_DRD_EXTENDED;
+}
+
+static inline int
+bcom_desc_is_drd(u32 desc)
+{
+ return !(desc & BCOM_LCD_MASK) && desc != BCOM_DESC_NOP;
+}
+
+static inline int
+bcom_desc_initiator(u32 desc)
+{
+ return (desc >> BCOM_DRD_INITIATOR_SHIFT) & 0x1f;
+}
+
+static inline void
+bcom_set_desc_initiator(u32 *desc, int initiator)
+{
+ *desc = (*desc & ~(0x1f << BCOM_DRD_INITIATOR_SHIFT)) |
+ ((initiator & 0x1f) << BCOM_DRD_INITIATOR_SHIFT);
+}
+
+
+static inline void
+bcom_set_task_pragma(int task, int pragma)
+{
+ u32 *fdt = &bcom_eng->tdt[task].fdt;
+ *fdt = (*fdt & ~0xff) | pragma;
+}
+
+static inline void
+bcom_set_task_auto_start(int task, int next_task)
+{
+ u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
+ out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
+}
+
+static inline void
+bcom_set_tcr_initiator(int task, int initiator)
+{
+ u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
+ out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8));
+}
+
+
+#endif /* __BESTCOMM_PRIV_H__ */
+
diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
new file mode 100644
index 0000000..b3f2ed1
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/sram.c
@@ -0,0 +1,177 @@
+/*
+ * Simple memory allocator for on-board SRAM
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+#include <asm/mmu.h>
+
+#include "sram.h"
+
+
+/* Struct keeping our 'state' */
+struct bcom_sram *bcom_sram = NULL;
+EXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */
+
+
+/* ======================================================================== */
+/* Public API */
+/* ======================================================================== */
+/* DO NOT USE in interrupts, if needed in irq handler, we should use the
+ _irqsave version of the spin_locks */
+
+int bcom_sram_init(struct device_node *sram_node, char *owner)
+{
+ int rv;
+ const u32 *regaddr_p;
+ u64 regaddr64, size64;
+ unsigned int psize;
+
+ /* Create our state struct */
+ if (bcom_sram) {
+ printk(KERN_ERR "%s: bcom_sram_init: "
+ "Already initialiwed !\n", owner);
+ return -EBUSY;
+ }
+
+ bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
+ if (!bcom_sram) {
+ printk(KERN_ERR "%s: bcom_sram_init: "
+ "Couldn't allocate internal state !\n", owner);
+ return -ENOMEM;
+ }
+
+ /* Get address and size of the sram */
+ regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
+ if (!regaddr_p) {
+ printk(KERN_ERR "%s: bcom_sram_init: "
+ "Invalid device node !\n", owner);
+ rv = -EINVAL;
+ goto error_free;
+ }
+
+ regaddr64 = of_translate_address(sram_node, regaddr_p);
+
+ bcom_sram->base_phys = (phys_addr_t) regaddr64;
+ bcom_sram->size = (unsigned int) size64;
+
+ /* Request region */
+ if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
+ printk(KERN_ERR "%s: bcom_sram_init: "
+ "Couln't request region !\n", owner);
+ rv = -EBUSY;
+ goto error_free;
+ }
+
+ /* Map SRAM */
+ /* sram is not really __iomem */
+ bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
+
+ if (!bcom_sram->base_virt) {
+ printk(KERN_ERR "%s: bcom_sram_init: "
+ "Map error SRAM zone 0x%08lx (0x%0x)!\n",
+ owner, bcom_sram->base_phys, bcom_sram->size );
+ rv = -ENOMEM;
+ goto error_release;
+ }
+
+ /* Create an rheap (defaults to 32 bits word alignment) */
+ bcom_sram->rh = rh_create(4);
+
+ /* Attach the free zones */
+#if 0
+ /* Currently disabled ... for future use only */
+ reg_addr_p = of_get_property(sram_node, "available", &psize);
+#else
+ regaddr_p = NULL;
+ psize = 0;
+#endif
+
+ if (!regaddr_p || !psize) {
+ /* Attach the whole zone */
+ rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
+ } else {
+ /* Attach each zone independently */
+ while (psize >= 2 * sizeof(u32)) {
+ phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
+ rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
+ regaddr_p += 2;
+ psize -= 2 * sizeof(u32);
+ }
+ }
+
+ /* Init our spinlock */
+ spin_lock_init(&bcom_sram->lock);
+
+ return 0;
+
+error_release:
+ release_mem_region(bcom_sram->base_phys, bcom_sram->size);
+error_free:
+ kfree(bcom_sram);
+ bcom_sram = NULL;
+
+ return rv;
+}
+EXPORT_SYMBOL_GPL(bcom_sram_init);
+
+void bcom_sram_cleanup(void)
+{
+ /* Free resources */
+ if (bcom_sram) {
+ rh_destroy(bcom_sram->rh);
+ iounmap((void __iomem *)bcom_sram->base_virt);
+ release_mem_region(bcom_sram->base_phys, bcom_sram->size);
+ kfree(bcom_sram);
+ bcom_sram = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
+
+void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
+{
+ unsigned long offset;
+
+ spin_lock(&bcom_sram->lock);
+ offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
+ spin_unlock(&bcom_sram->lock);
+
+ if (IS_ERR_VALUE(offset))
+ return NULL;
+
+ *phys = bcom_sram->base_phys + offset;
+ return bcom_sram->base_virt + offset;
+}
+EXPORT_SYMBOL_GPL(bcom_sram_alloc);
+
+void bcom_sram_free(void *ptr)
+{
+ unsigned long offset;
+
+ if (!ptr)
+ return;
+
+ offset = ptr - bcom_sram->base_virt;
+
+ spin_lock(&bcom_sram->lock);
+ rh_free(bcom_sram->rh, offset);
+ spin_unlock(&bcom_sram->lock);
+}
+EXPORT_SYMBOL_GPL(bcom_sram_free);
+
diff --git a/arch/powerpc/sysdev/bestcomm/sram.h b/arch/powerpc/sysdev/bestcomm/sram.h
new file mode 100644
index 0000000..b6d6689
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/sram.h
@@ -0,0 +1,54 @@
+/*
+ * Handling of a sram zone for bestcomm
+ *
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_SRAM_H__
+#define __BESTCOMM_SRAM_H__
+
+#include <asm/rheap.h>
+#include <asm/mmu.h>
+#include <linux/spinlock.h>
+
+
+/* Structure used internally */
+ /* The internals are here for the inline functions
+ * sake, certainly not for the user to mess with !
+ */
+struct bcom_sram {
+ phys_addr_t base_phys;
+ void *base_virt;
+ unsigned int size;
+ rh_info_t *rh;
+ spinlock_t lock;
+};
+
+extern struct bcom_sram *bcom_sram;
+
+
+/* Public API */
+extern int bcom_sram_init(struct device_node *sram_node, char *owner);
+extern void bcom_sram_cleanup(void);
+
+extern void* bcom_sram_alloc(int size, int align, phys_addr_t *phys);
+extern void bcom_sram_free(void *ptr);
+
+static inline phys_addr_t bcom_sram_va2pa(void *va) {
+ return bcom_sram->base_phys +
+ (unsigned long)(va - bcom_sram->base_virt);
+}
+
+static inline void *bcom_sram_pa2va(phys_addr_t pa) {
+ return bcom_sram->base_virt +
+ (unsigned long)(pa - bcom_sram->base_phys);
+}
+
+
+#endif /* __BESTCOMM_SRAM_H__ */
+
^ permalink raw reply related
* [PATCH v3 2/7] rheap: Changes config mechanism
From: Grant Likely @ 2007-10-14 22:48 UTC (permalink / raw)
To: galak, paulus, linuxppc-dev, tnt, domen.puncer
In-Reply-To: <20071014224724.14235.96152.stgit@trillian.cg.shawcable.net>
From: Sylvain Munaut <tnt@246tNt.com>
Instead of having in the makefile all the option that
requires rheap, we define a configuration symbol
and when needed we make sure it's selected.
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
arch/powerpc/Kconfig | 4 ++++
arch/powerpc/lib/Makefile | 5 +----
arch/powerpc/platforms/Kconfig | 2 ++
arch/powerpc/platforms/Kconfig.cputype | 1 +
arch/ppc/Kconfig | 6 ++++++
5 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 037664d..8300e6a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -698,3 +698,7 @@ source "crypto/Kconfig"
config PPC_CLOCK
bool
default n
+
+config PPC_LIB_RHEAP
+ bool
+
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 65d492e..4bb023f 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -14,7 +14,6 @@ endif
obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o
-obj-$(CONFIG_QUICC_ENGINE) += rheap.o
obj-$(CONFIG_XMON) += sstep.o
obj-$(CONFIG_KPROBES) += sstep.o
obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
@@ -23,6 +22,4 @@ ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.o
endif
-# Temporary hack until we have migrated to asm-powerpc
-obj-$(CONFIG_8xx) += rheap.o
-obj-$(CONFIG_CPM2) += rheap.o
+obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index cc6013f..3724cb4 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -264,6 +264,7 @@ config TAU_AVERAGE
config QUICC_ENGINE
bool
+ select PPC_LIB_RHEAP
help
The QUICC Engine (QE) is a new generation of communications
coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
@@ -274,6 +275,7 @@ config CPM2
bool
default n
select CPM
+ select PPC_LIB_RHEAP
help
The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 4c315be..3c7325e 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -37,6 +37,7 @@ config PPC_8xx
select FSL_SOC
select 8xx
select WANT_DEVICE_TREE
+ select PPC_LIB_RHEAP
config 40x
bool "AMCC 40x"
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 20dce46..607925c 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -102,6 +102,7 @@ config 44x
config 8xx
bool "8xx"
+ select PPC_LIB_RHEAP
config E200
bool "e200"
@@ -798,6 +799,7 @@ config CPM1
config CPM2
bool
depends on 8260 || MPC8560 || MPC8555
+ select PPC_LIB_RHEAP
default y
help
The CPM2 (Communications Processor Module) is a coprocessor on
@@ -1277,6 +1279,10 @@ config BOOT_LOAD
config PIN_TLB
bool "Pinned Kernel TLBs (860 ONLY)"
depends on ADVANCED_OPTIONS && 8xx
+
+config PPC_LIB_RHEAP
+ bool
+
endmenu
source "net/Kconfig"
^ permalink raw reply related
* [PATCH v3 0/7] Respin of bestcomm patches
From: Grant Likely @ 2007-10-14 22:48 UTC (permalink / raw)
To: galak, paulus, linuxppc-dev, tnt, domen.puncer
v3 fixes a regression building modules and integrates Domen's changes to
the FEC task.
Cheers,
g.
--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH v3 7/7] bestcomm: GenBD task support
From: Grant Likely @ 2007-10-14 22:48 UTC (permalink / raw)
To: galak, paulus, linuxppc-dev, tnt, domen.puncer
In-Reply-To: <20071014224724.14235.96152.stgit@trillian.cg.shawcable.net>
From: Sylvain Munaut <tnt@246tNt.com>
This is the microcode for the GenBD task and the associated
support code. This is a generic task that copy data to/from
a hardware FIFO. This is currently locked to 32bits wide
access but could be extended as needed.
The microcode itself comes directly from the offical
API (v2.2)
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
arch/powerpc/sysdev/bestcomm/Kconfig | 7 +
arch/powerpc/sysdev/bestcomm/Makefile | 2
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c | 63 +++++
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c | 69 +++++
arch/powerpc/sysdev/bestcomm/gen_bd.c | 260 ++++++++++++++++++++
arch/powerpc/sysdev/bestcomm/gen_bd.h | 48 ++++
6 files changed, 449 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
index 831763b..57cc565 100644
--- a/arch/powerpc/sysdev/bestcomm/Kconfig
+++ b/arch/powerpc/sysdev/bestcomm/Kconfig
@@ -30,3 +30,10 @@ config PPC_BESTCOMM_FEC
help
This option enables the support for the FEC tasks.
+config PPC_BESTCOMM_GEN_BD
+ tristate "Bestcomm GenBD tasks support"
+ depends on PPC_BESTCOMM
+ default n
+ help
+ This option enables the support for the GenBD tasks.
+
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
index 43046cf..095981a 100644
--- a/arch/powerpc/sysdev/bestcomm/Makefile
+++ b/arch/powerpc/sysdev/bestcomm/Makefile
@@ -5,8 +5,10 @@
bestcomm-core-objs := bestcomm.o sram.o
bestcomm-ata-objs := ata.o bcom_ata_task.o
bestcomm-fec-objs := fec.o bcom_fec_rx_task.o bcom_fec_tx_task.o
+bestcomm-gen-bd-objs := gen_bd.o bcom_gen_bd_rx_task.o bcom_gen_bd_tx_task.o
obj-y += bestcomm-core.o
obj-$(CONFIG_PPC_BESTCOMM_ATA) += bestcomm-ata.o
obj-$(CONFIG_PPC_BESTCOMM_FEC) += bestcomm-fec.o
+obj-$(CONFIG_PPC_BESTCOMM_GEN_BD) += bestcomm-gen-bd.o
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
new file mode 100644
index 0000000..efee022
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
@@ -0,0 +1,63 @@
+/*
+ * Bestcomm GenBD RX task microcode
+ *
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ * Jeff Gibbons <jeff.gibbons@appspec.com>
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 4 10:14:12 2006 GMT
+ *
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ * u32 magic;
+ * u8 desc_size;
+ * u8 var_size;
+ * u8 inc_size;
+ * u8 first_var;
+ * u8 reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_gen_bd_rx_task[] = {
+ /* header */
+ 0x4243544b,
+ 0x0d020409,
+ 0x00000000,
+ 0x00000000,
+
+ /* Task descriptors */
+ 0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */
+ 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
+ 0xb880025b, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */
+ 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+ 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */
+ 0xd9190240, /* LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */
+ 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
+ 0x07fecf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=31 WS=3 RS=3 */
+ 0x99190024, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc4 */
+ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+ 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */
+ 0x000001f8, /* NOP */
+
+ /* VAR[9]-VAR[10] */
+ 0x40000000,
+ 0x7fff7fff,
+
+ /* INC[0]-INC[3] */
+ 0x40000000,
+ 0xe0000000,
+ 0xa0000008,
+ 0x20000000,
+};
+
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
new file mode 100644
index 0000000..c605aa4
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
@@ -0,0 +1,69 @@
+/*
+ * Bestcomm GenBD TX task microcode
+ *
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ * Jeff Gibbons <jeff.gibbons@appspec.com>
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 4 10:14:12 2006 GMT
+ *
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ * u32 magic;
+ * u8 desc_size;
+ * u8 var_size;
+ * u8 inc_size;
+ * u8 first_var;
+ * u8 reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_gen_bd_tx_task[] = {
+ /* header */
+ 0x4243544b,
+ 0x0f040609,
+ 0x00000000,
+ 0x00000000,
+
+ /* Task descriptors */
+ 0x800220e3, /* LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
+ 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
+ 0xb8808264, /* LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */
+ 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+ 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+ 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */
+ 0xd9190300, /* LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */
+ 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
+ 0x03fec398, /* DRD1A: *idx0 = *idx3; FN=0 init=31 WS=3 RS=3 */
+ 0x9919826a, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */
+ 0x0feac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD INT init=31 WS=1 RS=1 */
+ 0x99190036, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
+ 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+ 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */
+ 0x000001f8, /* NOP */
+
+ /* VAR[9]-VAR[12] */
+ 0x40000000,
+ 0x7fff7fff,
+ 0x00000000,
+ 0x40000004,
+
+ /* INC[0]-INC[5] */
+ 0x40000000,
+ 0xe0000000,
+ 0xe0000000,
+ 0xa0000008,
+ 0x20000000,
+ 0x4000ffff,
+};
+
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
new file mode 100644
index 0000000..8d33eaf
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/gen_bd.c
@@ -0,0 +1,260 @@
+/*
+ * Driver for MPC52xx processor BestComm General Buffer Descriptor
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ * Jeff Gibbons <jeff.gibbons@appspec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+#include "bestcomm_priv.h"
+#include "gen_bd.h"
+
+
+/* ======================================================================== */
+/* Task image/var/inc */
+/* ======================================================================== */
+
+/* gen_bd tasks images */
+extern u32 bcom_gen_bd_rx_task[];
+extern u32 bcom_gen_bd_tx_task[];
+
+/* rx task vars that need to be set before enabling the task */
+struct bcom_gen_bd_rx_var {
+ u32 enable; /* (u16*) address of task's control register */
+ u32 fifo; /* (u32*) address of gen_bd's fifo */
+ u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
+ u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
+ u32 bd_start; /* (struct bcom_bd*) current bd */
+ u32 buffer_size; /* size of receive buffer */
+};
+
+/* rx task incs that need to be set before enabling the task */
+struct bcom_gen_bd_rx_inc {
+ u16 pad0;
+ s16 incr_bytes;
+ u16 pad1;
+ s16 incr_dst;
+};
+
+/* tx task vars that need to be set before enabling the task */
+struct bcom_gen_bd_tx_var {
+ u32 fifo; /* (u32*) address of gen_bd's fifo */
+ u32 enable; /* (u16*) address of task's control register */
+ u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
+ u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
+ u32 bd_start; /* (struct bcom_bd*) current bd */
+ u32 buffer_size; /* set by uCode for each packet */
+};
+
+/* tx task incs that need to be set before enabling the task */
+struct bcom_gen_bd_tx_inc {
+ u16 pad0;
+ s16 incr_bytes;
+ u16 pad1;
+ s16 incr_src;
+ u16 pad2;
+ s16 incr_src_ma;
+};
+
+/* private structure */
+struct bcom_gen_bd_priv {
+ phys_addr_t fifo;
+ int initiator;
+ int ipr;
+ int maxbufsize;
+};
+
+
+/* ======================================================================== */
+/* Task support code */
+/* ======================================================================== */
+
+struct bcom_task *
+bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
+ int initiator, int ipr, int maxbufsize)
+{
+ struct bcom_task *tsk;
+ struct bcom_gen_bd_priv *priv;
+
+ tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
+ sizeof(struct bcom_gen_bd_priv));
+ if (!tsk)
+ return NULL;
+
+ tsk->flags = BCOM_FLAGS_NONE;
+
+ priv = tsk->priv;
+ priv->fifo = fifo;
+ priv->initiator = initiator;
+ priv->ipr = ipr;
+ priv->maxbufsize = maxbufsize;
+
+ if (bcom_gen_bd_rx_reset(tsk)) {
+ bcom_task_free(tsk);
+ return NULL;
+ }
+
+ return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
+
+int
+bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+{
+ struct bcom_gen_bd_priv *priv = tsk->priv;
+ struct bcom_gen_bd_rx_var *var;
+ struct bcom_gen_bd_rx_inc *inc;
+
+ /* Shutdown the task */
+ bcom_disable_task(tsk->tasknum);
+
+ /* Reset the microcode */
+ var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);
+ inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);
+
+ if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))
+ return -1;
+
+ var->enable = bcom_eng->regs_base +
+ offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+ var->fifo = (u32) priv->fifo;
+ var->bd_base = tsk->bd_pa;
+ var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+ var->bd_start = tsk->bd_pa;
+ var->buffer_size = priv->maxbufsize;
+
+ inc->incr_bytes = -(s16)sizeof(u32);
+ inc->incr_dst = sizeof(u32);
+
+ /* Reset the BDs */
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+ memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
+ bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+ out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+ bcom_set_initiator(tsk->tasknum, priv->initiator);
+
+ out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
+
+void
+bcom_gen_bd_rx_release(struct bcom_task *tsk)
+{
+ /* Nothing special for the GenBD tasks */
+ bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
+
+
+extern struct bcom_task *
+bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
+ int initiator, int ipr)
+{
+ struct bcom_task *tsk;
+ struct bcom_gen_bd_priv *priv;
+
+ tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
+ sizeof(struct bcom_gen_bd_priv));
+ if (!tsk)
+ return NULL;
+
+ tsk->flags = BCOM_FLAGS_NONE;
+
+ priv = tsk->priv;
+ priv->fifo = fifo;
+ priv->initiator = initiator;
+ priv->ipr = ipr;
+
+ if (bcom_gen_bd_tx_reset(tsk)) {
+ bcom_task_free(tsk);
+ return NULL;
+ }
+
+ return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
+
+int
+bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+{
+ struct bcom_gen_bd_priv *priv = tsk->priv;
+ struct bcom_gen_bd_tx_var *var;
+ struct bcom_gen_bd_tx_inc *inc;
+
+ /* Shutdown the task */
+ bcom_disable_task(tsk->tasknum);
+
+ /* Reset the microcode */
+ var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);
+ inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);
+
+ if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))
+ return -1;
+
+ var->enable = bcom_eng->regs_base +
+ offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+ var->fifo = (u32) priv->fifo;
+ var->bd_base = tsk->bd_pa;
+ var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+ var->bd_start = tsk->bd_pa;
+
+ inc->incr_bytes = -(s16)sizeof(u32);
+ inc->incr_src = sizeof(u32);
+ inc->incr_src_ma = sizeof(u8);
+
+ /* Reset the BDs */
+ tsk->index = 0;
+ tsk->outdex = 0;
+
+ memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+ /* Configure some stuff */
+ bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
+ bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+ out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+ bcom_set_initiator(tsk->tasknum, priv->initiator);
+
+ out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
+
+void
+bcom_gen_bd_tx_release(struct bcom_task *tsk)
+{
+ /* Nothing special for the GenBD tasks */
+ bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
+
+
+MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
+MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.h b/arch/powerpc/sysdev/bestcomm/gen_bd.h
new file mode 100644
index 0000000..5b6fa80
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/gen_bd.h
@@ -0,0 +1,48 @@
+/*
+ * Header for Bestcomm General Buffer Descriptor tasks driver
+ *
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ * Jeff Gibbons <jeff.gibbons@appspec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ *
+ */
+
+#ifndef __BESTCOMM_GEN_BD_H__
+#define __BESTCOMM_GEN_BD_H__
+
+struct bcom_gen_bd {
+ u32 status;
+ u32 buf_pa;
+};
+
+
+extern struct bcom_task *
+bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
+ int initiator, int ipr, int maxbufsize);
+
+extern int
+bcom_gen_bd_rx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_gen_bd_rx_release(struct bcom_task *tsk);
+
+
+extern struct bcom_task *
+bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
+ int initiator, int ipr);
+
+extern int
+bcom_gen_bd_tx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_gen_bd_tx_release(struct bcom_task *tsk);
+
+
+#endif /* __BESTCOMM_GEN_BD_H__ */
+
^ permalink raw reply related
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