LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/2] perf_counter: powerpc: Add callchain support
From: Ingo Molnar @ 2009-06-27 16:58 UTC (permalink / raw)
  To: Peter Zijlstra; +Cc: Paul Mackerras, linux-kernel, linuxppc-dev
In-Reply-To: <1246091684.31755.210.camel@twins>


* Peter Zijlstra <a.p.zijlstra@chello.nl> wrote:

> On Sat, 2009-06-27 at 15:31 +1000, Paul Mackerras wrote:
> > +       if (regs) {
> > +               if (current_is_64bit())
> > +                       perf_callchain_user_64(regs, entry);
> > +               else
> > +                       perf_callchain_user_32(regs, entry);
> > +       }
> 
> Ingo do we need 32 on 64 stuff like that too?

hm, indeed.

	Ingo

^ permalink raw reply

* Re: [PATCH 2/2] perf_counter: powerpc: Add callchain support
From: Peter Zijlstra @ 2009-06-27  8:34 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: Ingo Molnar, linux-kernel, linuxppc-dev
In-Reply-To: <19013.44722.893263.275594@cargo.ozlabs.ibm.com>

On Sat, 2009-06-27 at 15:31 +1000, Paul Mackerras wrote:
> +       if (regs) {
> +               if (current_is_64bit())
> +                       perf_callchain_user_64(regs, entry);
> +               else
> +                       perf_callchain_user_32(regs, entry);
> +       }

Ingo do we need 32 on 64 stuff like that too?

^ permalink raw reply

* [PATCH 2/2] perf_counter: powerpc: Add callchain support
From: Paul Mackerras @ 2009-06-27  5:31 UTC (permalink / raw)
  To: Ingo Molnar, benh; +Cc: linuxppc-dev, Peter Zijlstra, linux-kernel
In-Reply-To: <19013.44646.549261.100582@cargo.ozlabs.ibm.com>

This adds support for tracing callchains for powerpc, both 32-bit
and 64-bit, and both in the kernel and userspace, from PMU interrupt
context.

The first three entries stored for each callchain are the NIP (next
instruction pointer), LR (link register), and the contents of the LR
save area in the second stack frame (the first is ignored because the
ABI convention on powerpc is that functions save their return address
in their caller's stack frame).  Because functions don't have to save
their return address (LR value) and don't have to establish a stack
frame, it's possible for either or both of LR and the second stack
frame's LR save area to have valid return addresses in them.  This
is basically impossible to disambiguate without either reading the
code or looking at auxiliary information such as CFI tables.  Since
we don't want to do that at interrupt time, we store both LR and the
second stack frame's LR save area.

Once we get past the second stack frame, there is no ambiguity; all
return addresses we get are reliable.

For kernel traces, we check whether they are valid kernel instruction
addresses and store zero instead if they are not (rather than
omitting them, which would make it impossible for userspace to know
which was which).  We also store zero instead of the second stack
frame's LR save area value if it is the same as LR.

For kernel traces, we check for interrupt frames, and for user traces,
we check for signal frames.  In each case, since we're starting a new
trace, we store a PERF_CONTEXT_KERNEL/USER marker so that userspace
knows that the next three entries are NIP, LR and the second stack fram=
e
for the interrupted context.

We read user memory with __get_user_inatomic.  On 64-bit, we set a flag=

to indicate that the data storage exception handler shouldn't call
hash_page on a MMU hashtable miss.  Instead we get a -EFAULT from
__get_user_inatomic and then read the Linux PTE and access the page
via the kernel linear mapping.  Since 64-bit doesn't use (or need)
highmem there is no need to do kmap_atomic.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/kernel/Makefile         |    2 +-
 arch/powerpc/kernel/perf_callchain.c |  544 ++++++++++++++++++++++++++=
++++++++
 2 files changed, 545 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/kernel/perf_callchain.c

diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefil=
e
index b73396b..9619285 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -97,7 +97,7 @@ obj64-$(CONFIG_AUDIT)=09=09+=3D compat_audit.o
=20
 obj-$(CONFIG_DYNAMIC_FTRACE)=09+=3D ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)=09+=3D ftrace.o
-obj-$(CONFIG_PPC_PERF_CTRS)=09+=3D perf_counter.o
+obj-$(CONFIG_PPC_PERF_CTRS)=09+=3D perf_counter.o perf_callchain.o
 obj64-$(CONFIG_PPC_PERF_CTRS)=09+=3D power4-pmu.o ppc970-pmu.o power5-=
pmu.o \
 =09=09=09=09   power5+-pmu.o power6-pmu.o power7-pmu.o
 obj32-$(CONFIG_PPC_PERF_CTRS)=09+=3D mpc7450-pmu.o
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel=
/perf_callchain.c
new file mode 100644
index 0000000..3cc1487
--- /dev/null
+++ b/arch/powerpc/kernel/perf_callchain.c
@@ -0,0 +1,544 @@
+/*
+ * Performance counter callchain support - powerpc architecture code
+ *
+ * Copyright =A9 2009 Paul Mackerras, IBM Corporation.
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/perf_counter.h>
+#include <linux/percpu.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/vdso.h>
+#ifdef CONFIG_PPC64
+#include "ppc32.h"
+#endif
+
+/*
+ * Store another value in a callchain_entry.
+ */
+static inline void callchain_store(struct perf_callchain_entry *entry,=
 u64 ip)
+{
+=09unsigned int nr =3D entry->nr;
+
+=09if (nr < PERF_MAX_STACK_DEPTH) {
+=09=09entry->ip[nr] =3D ip;
+=09=09entry->nr =3D nr + 1;
+=09}
+}
+
+/*
+ * Is sp valid as the address of the next kernel stack frame after pre=
v_sp?
+ * The next frame may be in a different stack area but should not go
+ * back down in the same stack area.
+ */
+static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
+{
+=09if (sp & 0xf)
+=09=09return 0;=09=09/* must be 16-byte aligned */
+=09if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+=09=09return 0;
+=09if (sp >=3D prev_sp + STACK_FRAME_OVERHEAD)
+=09=09return 1;
+=09/*
+=09 * sp could decrease when we jump off an interrupt stack
+=09 * back to the regular process stack.
+=09 */
+=09if ((sp & ~(THREAD_SIZE - 1)) !=3D (prev_sp & ~(THREAD_SIZE - 1)))
+=09=09return 1;
+=09return 0;
+}
+
+static void perf_callchain_kernel(struct pt_regs *regs,
+=09=09=09=09  struct perf_callchain_entry *entry)
+{
+=09unsigned long sp, next_sp;
+=09unsigned long next_ip;
+=09unsigned long lr;
+=09long level =3D 0;
+=09unsigned long *fp;
+
+=09lr =3D regs->link;
+=09sp =3D regs->gpr[1];
+=09callchain_store(entry, PERF_CONTEXT_KERNEL);
+=09callchain_store(entry, regs->nip);
+
+=09if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
+=09=09return;
+
+=09for (;;) {
+=09=09fp =3D (unsigned long *) sp;
+=09=09next_sp =3D fp[0];
+
+=09=09if (next_sp =3D=3D sp + STACK_INT_FRAME_SIZE &&
+=09=09    fp[STACK_FRAME_MARKER] =3D=3D STACK_FRAME_REGS_MARKER) {
+=09=09=09/*
+=09=09=09 * This looks like an interrupt frame for an
+=09=09=09 * interrupt that occurred in the kernel
+=09=09=09 */
+=09=09=09regs =3D (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
+=09=09=09next_ip =3D regs->nip;
+=09=09=09lr =3D regs->link;
+=09=09=09level =3D 0;
+=09=09=09callchain_store(entry, PERF_CONTEXT_KERNEL);
+
+=09=09} else {
+=09=09=09if (level =3D=3D 0)
+=09=09=09=09next_ip =3D lr;
+=09=09=09else
+=09=09=09=09next_ip =3D fp[STACK_FRAME_LR_SAVE];
+
+=09=09=09/*
+=09=09=09 * We can't tell which of the first two addresses
+=09=09=09 * we get are valid, but we can filter out the
+=09=09=09 * obviously bogus ones here.  We replace them
+=09=09=09 * with 0 rather than removing them entirely so
+=09=09=09 * that userspace can tell which is which.
+=09=09=09 */
+=09=09=09if ((level =3D=3D 1 && next_ip =3D=3D lr) ||
+=09=09=09    (level <=3D 1 && !kernel_text_address(next_ip)))
+=09=09=09=09next_ip =3D 0;
+
+=09=09=09++level;
+=09=09}
+
+=09=09callchain_store(entry, next_ip);
+=09=09if (!valid_next_sp(next_sp, sp))
+=09=09=09return;
+=09=09sp =3D next_sp;
+=09}
+}
+
+#ifdef CONFIG_PPC64
+/*
+ * On 64-bit we don't want to invoke hash_page on user addresses from
+ * interrupt context, so if the access faults, we read the page tables=

+ * to find which page (if any) is mapped and access it directly.
+ */
+static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
+{
+=09pgd_t *pgdir;
+=09pte_t *ptep, pte;
+=09int pagesize;
+=09unsigned long addr =3D (unsigned long) ptr;
+=09unsigned long offset;
+=09unsigned long pfn;
+=09void *kaddr;
+
+=09pgdir =3D current->mm->pgd;
+=09if (!pgdir)
+=09=09return -EFAULT;
+
+=09pagesize =3D get_slice_psize(current->mm, addr);
+
+=09/* align address to page boundary */
+=09offset =3D addr & ((1ul << mmu_psize_defs[pagesize].shift) - 1);
+=09addr -=3D offset;
+
+=09if (HPAGE_SHIFT && mmu_huge_psizes[pagesize])
+=09=09ptep =3D huge_pte_offset(current->mm, addr);
+=09else
+=09=09ptep =3D find_linux_pte(pgdir, addr);
+
+=09if (ptep =3D=3D NULL)
+=09=09return -EFAULT;
+=09pte =3D *ptep;
+=09if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
+=09=09return -EFAULT;
+=09pfn =3D pte_pfn(pte);
+=09if (!page_is_ram(pfn))
+=09=09return -EFAULT;
+
+=09/* no highmem to worry about here */
+=09kaddr =3D pfn_to_kaddr(pfn);
+=09memcpy(ret, kaddr + offset, nb);
+=09return 0;
+}
+
+static int read_user_stack_64(unsigned long __user *ptr, unsigned long=
 *ret)
+{
+=09int err;
+
+=09if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
+=09    ((unsigned long)ptr & 7))
+=09=09return -EFAULT;
+
+=09/*
+=09 * On 64-bit, tell the DSI handler not to call hash_page
+=09 * if this access causes a hashtable miss fault.
+=09 */
+=09get_paca()->in_pmu_nmi =3D 1;
+=09barrier();
+=09err =3D __get_user_inatomic(*ret, ptr);
+=09barrier();
+=09get_paca()->in_pmu_nmi =3D 0;
+
+=09if (!err)
+=09=09return 0;
+
+=09return read_user_stack_slow(ptr, ret, 8);
+}
+
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *=
ret)
+{
+=09int err;
+
+=09if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+=09    ((unsigned long)ptr & 3))
+=09=09return -EFAULT;
+
+=09/*
+=09 * On 64-bit, tell the DSI handler not to call hash_page
+=09 * if this access causes a hashtable miss fault.
+=09 */
+=09get_paca()->in_pmu_nmi =3D 1;
+=09barrier();
+=09err =3D __get_user_inatomic(*ret, ptr);
+=09barrier();
+=09get_paca()->in_pmu_nmi =3D 0;
+
+=09if (!err)
+=09=09return 0;
+
+=09return read_user_stack_slow(ptr, ret, 4);
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+=09if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 3=
2)
+=09=09return 0;
+=09return 1;
+}
+
+/*
+ * 64-bit user processes use the same stack frame for RT and non-RT si=
gnals.
+ */
+struct signal_frame_64 {
+=09char=09=09dummy[__SIGNAL_FRAMESIZE];
+=09struct ucontext=09uc;
+=09unsigned long=09unused[2];
+=09unsigned int=09tramp[6];
+=09struct siginfo=09*pinfo;
+=09void=09=09*puc;
+=09struct siginfo=09info;
+=09char=09=09abigap[288];
+};
+
+static int is_sigreturn_64_address(unsigned long nip, unsigned long fp=
)
+{
+=09if (nip =3D=3D fp + offsetof(struct signal_frame_64, tramp))
+=09=09return 1;
+=09if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
+=09    nip =3D=3D current->mm->context.vdso_base + vdso64_rt_sigtramp)=

+=09=09return 1;
+=09return 0;
+}
+
+/*
+ * Do some sanity checking on the signal frame pointed to by sp.
+ * We check the pinfo and puc pointers in the frame.
+ */
+static int sane_signal_64_frame(unsigned long sp)
+{
+=09struct signal_frame_64 __user *sf;
+=09unsigned long pinfo, puc;
+
+=09sf =3D (struct signal_frame_64 __user *) sp;
+=09if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo)=
 ||
+=09    read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
+=09=09return 0;
+=09return pinfo =3D=3D (unsigned long) &sf->info &&
+=09=09puc =3D=3D (unsigned long) &sf->uc;
+}
+
+static void perf_callchain_user_64(struct pt_regs *regs,
+=09=09=09=09   struct perf_callchain_entry *entry)
+{
+=09unsigned long sp, next_sp;
+=09unsigned long next_ip;
+=09unsigned long lr;
+=09long level =3D 0;
+=09struct signal_frame_64 __user *sigframe;
+=09unsigned long __user *fp, *uregs;
+
+=09next_ip =3D regs->nip;
+=09lr =3D regs->link;
+=09sp =3D regs->gpr[1];
+=09callchain_store(entry, PERF_CONTEXT_USER);
+=09callchain_store(entry, next_ip);
+
+=09for (;;) {
+=09=09fp =3D (unsigned long __user *) sp;
+=09=09if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
+=09=09=09return;
+=09=09if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
+=09=09=09return;
+
+=09=09/*
+=09=09 * Note: the next_sp - sp >=3D signal frame size check
+=09=09 * is true when next_sp < sp, which can happen when
+=09=09 * transitioning from an alternate signal stack to the
+=09=09 * normal stack.
+=09=09 */
+=09=09if (next_sp - sp >=3D sizeof(struct signal_frame_64) &&
+=09=09    (is_sigreturn_64_address(next_ip, sp) ||
+=09=09     (level <=3D 1 && is_sigreturn_64_address(lr, sp))) &&
+=09=09    sane_signal_64_frame(sp)) {
+=09=09=09/*
+=09=09=09 * This looks like an signal frame
+=09=09=09 */
+=09=09=09sigframe =3D (struct signal_frame_64 __user *) sp;
+=09=09=09uregs =3D sigframe->uc.uc_mcontext.gp_regs;
+=09=09=09if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
+=09=09=09    read_user_stack_64(&uregs[PT_LNK], &lr) ||
+=09=09=09    read_user_stack_64(&uregs[PT_R1], &sp))
+=09=09=09=09return;
+=09=09=09level =3D 0;
+=09=09=09callchain_store(entry, PERF_CONTEXT_USER);
+=09=09=09callchain_store(entry, next_ip);
+=09=09=09continue;
+=09=09}
+
+=09=09if (level =3D=3D 0)
+=09=09=09next_ip =3D lr;
+=09=09callchain_store(entry, next_ip);
+=09=09++level;
+=09=09sp =3D next_sp;
+=09}
+}
+
+static inline int current_is_64bit(void)
+{
+=09/*
+=09 * We can't use test_thread_flag() here because we may be on an
+=09 * interrupt stack, and the thread flags don't get copied over
+=09 * from the thread_info on the main stack to the interrupt stack.
+=09 */
+=09return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
+}
+
+#else  /* CONFIG_PPC64 */
+/*
+ * On 32-bit we just access the address and let hash_page create a
+ * HPTE if necessary, so there is no need to fall back to reading
+ * the page tables.  Since this is called at interrupt level,
+ * do_page_fault() won't treat a DSI as a page fault.
+ */
+static int read_user_stack_32(unsigned int __user *ptr, unsigned int *=
ret)
+{
+=09if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
+=09    ((unsigned long)ptr & 3))
+=09=09return -EFAULT;
+
+=09return __get_user_inatomic(*ret, ptr);
+}
+
+static inline void perf_callchain_user_64(struct pt_regs *regs,
+=09=09=09=09=09  struct perf_callchain_entry *entry)
+{
+}
+
+static inline int current_is_64bit(void)
+{
+=09return 0;
+}
+
+static inline int valid_user_sp(unsigned long sp, int is_64)
+{
+=09if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
+=09=09return 0;
+=09return 1;
+}
+
+#define __SIGNAL_FRAMESIZE32=09__SIGNAL_FRAMESIZE
+#define sigcontext32=09=09sigcontext
+#define mcontext32=09=09mcontext
+#define ucontext32=09=09ucontext
+#define compat_siginfo_t=09struct siginfo
+
+#endif /* CONFIG_PPC64 */
+
+/*
+ * Layout for non-RT signal frames
+ */
+struct signal_frame_32 {
+=09char=09=09=09dummy[__SIGNAL_FRAMESIZE32];
+=09struct sigcontext32=09sctx;
+=09struct mcontext32=09mctx;
+=09int=09=09=09abigap[56];
+};
+
+/*
+ * Layout for RT signal frames
+ */
+struct rt_signal_frame_32 {
+=09char=09=09=09dummy[__SIGNAL_FRAMESIZE32 + 16];
+=09compat_siginfo_t=09info;
+=09struct ucontext32=09uc;
+=09int=09=09=09abigap[56];
+};
+
+static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
+{
+=09if (nip =3D=3D fp + offsetof(struct signal_frame_32, mctx.mc_pad))
+=09=09return 1;
+=09if (vdso32_sigtramp && current->mm->context.vdso_base &&
+=09    nip =3D=3D current->mm->context.vdso_base + vdso32_sigtramp)
+=09=09return 1;
+=09return 0;
+}
+
+static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int f=
p)
+{
+=09if (nip =3D=3D fp + offsetof(struct rt_signal_frame_32,
+=09=09=09=09 uc.uc_mcontext.mc_pad))
+=09=09return 1;
+=09if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
+=09    nip =3D=3D current->mm->context.vdso_base + vdso32_rt_sigtramp)=

+=09=09return 1;
+=09return 0;
+}
+
+static int sane_signal_32_frame(unsigned int sp)
+{
+=09struct signal_frame_32 __user *sf;
+=09unsigned int regs;
+
+=09sf =3D (struct signal_frame_32 __user *) (unsigned long) sp;
+=09if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &reg=
s))
+=09=09return 0;
+=09return regs =3D=3D (unsigned long) &sf->mctx;
+}
+
+static int sane_rt_signal_32_frame(unsigned int sp)
+{
+=09struct rt_signal_frame_32 __user *sf;
+=09unsigned int regs;
+
+=09sf =3D (struct rt_signal_frame_32 __user *) (unsigned long) sp;
+=09if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &re=
gs))
+=09=09return 0;
+=09return regs =3D=3D (unsigned long) &sf->uc.uc_mcontext;
+}
+
+static unsigned int __user *signal_frame_32_regs(unsigned int sp,
+=09=09=09=09unsigned int next_sp, unsigned int next_ip)
+{
+=09struct mcontext32 __user *mctx =3D NULL;
+=09struct signal_frame_32 __user *sf;
+=09struct rt_signal_frame_32 __user *rt_sf;
+
+=09/*
+=09 * Note: the next_sp - sp >=3D signal frame size check
+=09 * is true when next_sp < sp, for example, when
+=09 * transitioning from an alternate signal stack to the
+=09 * normal stack.
+=09 */
+=09if (next_sp - sp >=3D sizeof(struct signal_frame_32) &&
+=09    is_sigreturn_32_address(next_ip, sp) &&
+=09    sane_signal_32_frame(sp)) {
+=09=09sf =3D (struct signal_frame_32 __user *) (unsigned long) sp;
+=09=09mctx =3D &sf->mctx;
+=09}
+
+=09if (!mctx && next_sp - sp >=3D sizeof(struct rt_signal_frame_32) &&=

+=09    is_rt_sigreturn_32_address(next_ip, sp) &&
+=09    sane_rt_signal_32_frame(sp)) {
+=09=09rt_sf =3D (struct rt_signal_frame_32 __user *) (unsigned long) s=
p;
+=09=09mctx =3D &rt_sf->uc.uc_mcontext;
+=09}
+
+=09if (!mctx)
+=09=09return NULL;
+=09return mctx->mc_gregs;
+}
+
+static void perf_callchain_user_32(struct pt_regs *regs,
+=09=09=09=09   struct perf_callchain_entry *entry)
+{
+=09unsigned int sp, next_sp;
+=09unsigned int next_ip;
+=09unsigned int lr;
+=09long level =3D 0;
+=09unsigned int __user *fp, *uregs;
+
+=09next_ip =3D regs->nip;
+=09lr =3D regs->link;
+=09sp =3D regs->gpr[1];
+=09callchain_store(entry, PERF_CONTEXT_USER);
+=09callchain_store(entry, next_ip);
+
+=09while (entry->nr < PERF_MAX_STACK_DEPTH) {
+=09=09fp =3D (unsigned int __user *) (unsigned long) sp;
+=09=09if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
+=09=09=09return;
+=09=09if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
+=09=09=09return;
+
+=09=09uregs =3D signal_frame_32_regs(sp, next_sp, next_ip);
+=09=09if (!uregs && level <=3D 1)
+=09=09=09uregs =3D signal_frame_32_regs(sp, next_sp, lr);
+=09=09if (uregs) {
+=09=09=09/*
+=09=09=09 * This looks like an signal frame, so restart
+=09=09=09 * the stack trace with the values in it.
+=09=09=09 */
+=09=09=09if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
+=09=09=09    read_user_stack_32(&uregs[PT_LNK], &lr) ||
+=09=09=09    read_user_stack_32(&uregs[PT_R1], &sp))
+=09=09=09=09return;
+=09=09=09level =3D 0;
+=09=09=09callchain_store(entry, PERF_CONTEXT_USER);
+=09=09=09callchain_store(entry, next_ip);
+=09=09=09continue;
+=09=09}
+
+=09=09if (level =3D=3D 0)
+=09=09=09next_ip =3D lr;
+=09=09callchain_store(entry, next_ip);
+=09=09++level;
+=09=09sp =3D next_sp;
+=09}
+}
+
+/*
+ * Since we can't get PMU interrupts inside a PMU interrupt handler,
+ * we don't need separate irq and nmi entries here.
+ */
+static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
+
+struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+{
+=09struct perf_callchain_entry *entry =3D &__get_cpu_var(callchain);
+
+=09entry->nr =3D 0;
+
+=09if (current->pid =3D=3D 0)=09=09/* idle task? */
+=09=09return entry;
+
+=09if (!user_mode(regs)) {
+=09=09perf_callchain_kernel(regs, entry);
+=09=09if (current->mm)
+=09=09=09regs =3D task_pt_regs(current);
+=09=09else
+=09=09=09regs =3D NULL;
+=09}
+
+=09if (regs) {
+=09=09if (current_is_64bit())
+=09=09=09perf_callchain_user_64(regs, entry);
+=09=09else
+=09=09=09perf_callchain_user_32(regs, entry);
+=09}
+
+=09return entry;
+}
--=20
1.6.0.4

^ permalink raw reply related

* [PATCH 1/2] powerpc: Allow perf_counters to access user memory at interrupt time
From: Paul Mackerras @ 2009-06-27  5:30 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev, Ingo Molnar, Peter Zijlstra, linux-kernel

This provides a mechanism to allow the perf_counters code to access
user memory in a PMU interrupt routine on a 64-bit kernel.  Such an
access can cause a SLB miss interrupt and/or a MMU hash table miss
interrupt.

An SLB miss interrupt on a user address will update the slb_cache and
slb_cache_ptr fields in the paca.  This is OK except in the case where
a PMU interrupt occurs in switch_slb, which also accesses those fields.
To prevent this, we hard-disable interrupts in switch_slb.  Interrupts
are already soft-disabled in switch-slb, and will get hard-enabled
when they get soft-enabled later.

If a MMU hashtable miss interrupt occurs, normally we would call
hash_page to look up the Linux PTE for the address and create a HPTE.
However, hash_page is fairly complex and takes some locks, so to
avoid the possibility of deadlock, we add a flag to the paca to
indicate to the MMU hashtable miss handler that it should not call
hash_page but instead treat it like a bad access that will get
reported up through the exception table mechanism.  The PMU interrupt
code should then set this flag (get_paca()->in_pmu_nmi) and use
__get_user_inatomic to read user memory.  If there is no HPTE for
the address, __get_user_inatomic will return -EFAULT.

On a 32-bit processor, there is no SLB.  The 32-bit hash_page appears
to be safe to call in an interrupt handler since we don't do soft
disabling of interrupts on 32-bit, and the only lock that hash_page
takes is the mmu_hash_lock, which is always taken with interrupts
hard-disabled.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 arch/powerpc/include/asm/paca.h      |    3 ++-
 arch/powerpc/kernel/asm-offsets.c    |    2 ++
 arch/powerpc/kernel/exceptions-64s.S |   21 +++++++++++++++++++++
 arch/powerpc/mm/slb.c                |   10 +++++++++-
 4 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index c8a3cbf..17b29b1 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -105,7 +105,8 @@ struct paca_struct {
 	u8 soft_enabled;		/* irq soft-enable flag */
 	u8 hard_enabled;		/* set if irqs are enabled in MSR */
 	u8 io_sync;			/* writel() needs spin_unlock sync */
-	u8 perf_counter_pending;	/* PM interrupt while soft-disabled */
+	u8 perf_counter_pending;	/* perf_counter stuff needs wakeup */
+	u8 in_pmu_nmi;			/* PM interrupt while soft-disabled */
 
 	/* Stuff for accurate time accounting */
 	u64 user_time;			/* accumulated usermode TB ticks */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 561b646..5347780 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -130,6 +130,7 @@ int main(void)
 	DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
 	DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
 	DEFINE(PACAPERFPEND, offsetof(struct paca_struct, perf_counter_pending));
+	DEFINE(PACAPERFNMI, offsetof(struct paca_struct, in_pmu_nmi));
 	DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
 #ifdef CONFIG_PPC_MM_SLICES
 	DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
@@ -398,6 +399,7 @@ int main(void)
 	DEFINE(VCPU_TIMING_LAST_ENTER_TBL, offsetof(struct kvm_vcpu,
 					arch.timing_last_enter.tv32.tbl));
 #endif
+	DEFINE(SIGSEGV, SIGSEGV);
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index eb89811..02d96b0 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -722,6 +722,12 @@ _STATIC(do_hash_page)
 	std	r3,_DAR(r1)
 	std	r4,_DSISR(r1)
 
+#ifdef CONFIG_PERF_COUNTERS
+	lbz	r0,PACAPERFNMI(r13)
+	cmpwi	r0,0
+	bne	77f			/* if we don't want to hash_page now */
+#endif /* CONFIG_PERF_COUNTERS */
+
 	andis.	r0,r4,0xa450		/* weird error? */
 	bne-	handle_page_fault	/* if not, try to insert a HPTE */
 BEGIN_FTR_SECTION
@@ -833,6 +839,21 @@ handle_page_fault:
 	bl	.low_hash_fault
 	b	.ret_from_except
 
+#ifdef CONFIG_PERF_COUNTERS
+/*
+ * We come here as a result of a DSI when accessing memory (possibly
+ * user memory) inside a PMU interrupt that occurred while interrupts
+ * were soft-disabled, so we just want to invoke the exception handler
+ * for the access, or panic if there isn't a handler.
+ */
+77:	bl	.save_nvgprs
+	mr	r4,r3
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r5,SIGSEGV
+	bl	.bad_page_fault
+	b	.ret_from_except
+#endif
+
 	/* here we have a segment miss */
 do_ste_alloc:
 	bl	.ste_allocate		/* try to insert stab entry */
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 3b52c80..ebfb8df 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -187,12 +187,20 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2)
 /* Flush all user entries from the segment table of the current processor. */
 void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
 {
-	unsigned long offset = get_paca()->slb_cache_ptr;
+	unsigned long offset;
 	unsigned long slbie_data = 0;
 	unsigned long pc = KSTK_EIP(tsk);
 	unsigned long stack = KSTK_ESP(tsk);
 	unsigned long unmapped_base;
 
+	/*
+	 * We need interrupts hard-disabled here, not just soft-disabled,
+	 * so that a PMU interrupt can't occur, which might try to access
+	 * user memory (to get a stack trace) and possible cause an SLB miss
+	 * which would update the slb_cache/slb_cache_ptr fields in the PACA.
+	 */
+	hard_irq_disable();
+	offset = get_paca()->slb_cache_ptr;
 	if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) &&
 	    offset <= SLB_CACHE_ENTRIES) {
 		int i;
-- 
1.6.0.4

^ permalink raw reply related

* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Alan Stern @ 2009-06-27  1:33 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, USB list, abhishekkumar, bugme-daemon
In-Reply-To: <4A454616.7040501@am.sony.com>

On Fri, 26 Jun 2009, Geoff Levand wrote:

> > Where is the information about the hardware errata you mentioned?
> 
> Sorry, I should have mentioned it.  Unfortunately, that info is not
> in the public as far as I know.  I think only someone with access
> to those will be able to work on this fix.

Okay, then I guess there's nothing more I can do regarding Bug #13304.  
Can you take it over?

Alan Stern

^ permalink raw reply

* Re: [PATCH 1/4] of/mdio: Add fixed link support
From: Anton Vorontsov @ 2009-06-27  0:11 UTC (permalink / raw)
  To: Grant Likely; +Cc: netdev, Li Yang, Andy Fleming, David Miller, linuxppc-dev
In-Reply-To: <fa686aa40906261633y502f0ed2jebc58f9160c683ce@mail.gmail.com>

On Fri, Jun 26, 2009 at 05:33:26PM -0600, Grant Likely wrote:
> On Fri, Jun 26, 2009 at 4:29 PM, Anton
> Vorontsov<avorontsov@ru.mvista.com> wrote:
> > Currently the fixed link support is broken for all OF ethernet drivers,
> > an "OF MDIO rework" removed most of the support. Instead of re-adding
> > fixed-link stuff to the drivers, add the support to a framework, so we
> > won't duplicate any code.
> >
> > With this patch, if a node pointer is NULL, then of_phy_connect() will
> > try to find ethernet device's node, then will look for fixed-link
> > property, and if specified, it connects PHY as usual, via bus_id (fixed
> > link PHYs do not have any device tree nodes associated with them).
> >
> > Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> 
> Ugh.  I do not like this approach.  I did not intend to break fixed
> links, but I do not think that this approach is the right fix.  There
> are several problems.
> 
> I don't like the fixed.c approach of creating a dummy phy to begin
> with.  I think it is an abuse of the device model to register a dummy
> mii_bus and have dummy devices registered on it.  It is a lot of code
> for what should be a very simple thing.  In particular, if a PHY is
> not specified, then the driver should use a static link configuration.
>  This is trivial to implement in an Ethernet driver and I do not think
> the dummy phy adds anything.

Dummy PHYs add more than you think, for example you'll have to
refactor or duplicate the code that is responsible for MAC settings
for a given mode (10/100/100, duplex, pause), and you'll have to
do netif_carrier_* handling yourself.

Not a problem per se, but you'll have to address this, and you'll
have two paths in the drivers.

> It hooks into the initialization path of *all* OF enabled net drivers,
> whether it wants it or not.  ie. The MPC5200 FEC driver does not want
> it because the fixed-link property is not part of the mpc5200-fec
> binding; it uses a current-speed property instead.  'fixed-link' has
> not been agreed upon to be applicable to all Ethernet bindings, and
> I'm not convinced that the format of it won't need to be changed for
> future Ethernet bindings.  A function for parsing fixed-link should be
> a library function that a driver can choose to call out to.  It should
> not be welded into the init path.
> 
> I also think parsing the device tree at device open time (when
> of_phy_connect is usually called) is best to be avoided.  fixed-link
> parsing should really happen at probe time and the values cached IMHO.
>  It's probably not significant, but I'd like to keep device tree reads
> constrained in the cold path (driver probe time) as opposed to the hot
> (or slightly less cool) device open path.

open() time isn't a hot path at all.

> Instead, I think that each driver should be more graceful about
> missing phy pointers and the init path should call out to a fixed-link
> parser function that sets the initial link settings.  Probably less
> than 5 lines of code per driver.
> 
> I'm sorry about breaking it.  It was my fault, and I'd be happy to fix
> it if you'd like me to,

Please do.

> but I don't think that this patch is the right
> approach.

OK, fine by me if you think you can do this stuff better. :-)

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH 0/4 for 2.6.31] NET: Revive fixed link support
From: Grant Likely @ 2009-06-26 23:35 UTC (permalink / raw)
  To: avorontsov; +Cc: netdev, Li Yang, Andy Fleming, David Miller, linuxppc-dev
In-Reply-To: <20090626222900.GA14594@oksana.dev.rtsoft.ru>

On Fri, Jun 26, 2009 at 4:29 PM, Anton
Vorontsov<avorontsov@ru.mvista.com> wrote:
> Hi all,
>
> The fixed link support is broken since The Big OF MDIO Rework,
> the rework simply removed most of the code that was needed for
> fixed links.
>
> Too bad I didn't notice this earlier, I saw a bunch of patches
> on the ml, but unfortunately I didn't look very close presuming
> that Grant knew what he was doing. :-) And obviously I didn't
> test linux-next on anything that requires a fixed link.

Apparently I didn't.  sorry.

> Anyway, here are four patches. The first one adds the fixed link
> support to a framework, otherwise we'd duplicate the code across
> the drivers (as we did previously), and I tried to keep drivers'
> changes minimal.

As I described in my previous email, I don't think this is a good
approach and I don't think it should be merged.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 1/4] of/mdio: Add fixed link support
From: Grant Likely @ 2009-06-26 23:33 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: netdev, Li Yang, Andy Fleming, David Miller, linuxppc-dev
In-Reply-To: <20090626222945.GA32487@oksana.dev.rtsoft.ru>

On Fri, Jun 26, 2009 at 4:29 PM, Anton
Vorontsov<avorontsov@ru.mvista.com> wrote:
> Currently the fixed link support is broken for all OF ethernet drivers,
> an "OF MDIO rework" removed most of the support. Instead of re-adding
> fixed-link stuff to the drivers, add the support to a framework, so we
> won't duplicate any code.
>
> With this patch, if a node pointer is NULL, then of_phy_connect() will
> try to find ethernet device's node, then will look for fixed-link
> property, and if specified, it connects PHY as usual, via bus_id (fixed
> link PHYs do not have any device tree nodes associated with them).
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>

Ugh.  I do not like this approach.  I did not intend to break fixed
links, but I do not think that this approach is the right fix.  There
are several problems.

I don't like the fixed.c approach of creating a dummy phy to begin
with.  I think it is an abuse of the device model to register a dummy
mii_bus and have dummy devices registered on it.  It is a lot of code
for what should be a very simple thing.  In particular, if a PHY is
not specified, then the driver should use a static link configuration.
 This is trivial to implement in an Ethernet driver and I do not think
the dummy phy adds anything.

It hooks into the initialization path of *all* OF enabled net drivers,
whether it wants it or not.  ie. The MPC5200 FEC driver does not want
it because the fixed-link property is not part of the mpc5200-fec
binding; it uses a current-speed property instead.  'fixed-link' has
not been agreed upon to be applicable to all Ethernet bindings, and
I'm not convinced that the format of it won't need to be changed for
future Ethernet bindings.  A function for parsing fixed-link should be
a library function that a driver can choose to call out to.  It should
not be welded into the init path.

I also think parsing the device tree at device open time (when
of_phy_connect is usually called) is best to be avoided.  fixed-link
parsing should really happen at probe time and the values cached IMHO.
 It's probably not significant, but I'd like to keep device tree reads
constrained in the cold path (driver probe time) as opposed to the hot
(or slightly less cool) device open path.

Instead, I think that each driver should be more graceful about
missing phy pointers and the init path should call out to a fixed-link
parser function that sets the initial link settings.  Probably less
than 5 lines of code per driver.

I'm sorry about breaking it.  It was my fault, and I'd be happy to fix
it if you'd like me to, but I don't think that this patch is the right
approach.

g.

> ---
> =A0drivers/of/of_mdio.c | =A0 45 ++++++++++++++++++++++++++++++++++++++++=
+----
> =A01 files changed, 41 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
> index aee967d..cfd876a 100644
> --- a/drivers/of/of_mdio.c
> +++ b/drivers/of/of_mdio.c
> @@ -9,6 +9,10 @@
> =A0* out of the OpenFirmware device tree and using it to populate an mii_=
bus.
> =A0*/
>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/netdevice.h>
> +#include <linux/err.h>
> =A0#include <linux/phy.h>
> =A0#include <linux/of.h>
> =A0#include <linux/of_mdio.h>
> @@ -129,11 +133,44 @@ struct phy_device *of_phy_connect(struct net_device=
 *dev,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void (=
*hndlr)(struct net_device *), u32 flags,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0phy_in=
terface_t iface)
> =A0{
> - =A0 =A0 =A0 struct phy_device *phy =3D of_phy_find_device(phy_np);
> + =A0 =A0 =A0 struct phy_device *phy =3D NULL;
> +
> + =A0 =A0 =A0 if (phy_np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int ret;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy =3D of_phy_find_device(phy_np);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!phy)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D phy_connect_direct(dev, phy, hndlr,=
 flags, iface);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ret)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> + =A0 =A0 =A0 } else if (dev->dev.parent) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct device_node *net_np;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 const u32 *phy_id;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 char *bus_id;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int sz;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 net_np =3D dev_archdata_get_node(&dev->dev.=
parent->archdata);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!net_np)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy_id =3D of_get_property(net_np, "fixed-l=
ink", &sz);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!phy_id || sz < sizeof(*phy_id))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bus_id =3D kasprintf(GFP_KERNEL, PHY_ID_FMT=
, "0", phy_id[0]);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!bus_id) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&dev->dev, "could n=
ot allocate memory\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>
> - =A0 =A0 =A0 if (!phy)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 phy =3D phy_connect(dev, bus_id, hndlr, 0, =
iface);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 kfree(bus_id);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (IS_ERR(phy))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> + =A0 =A0 =A0 }
>
> - =A0 =A0 =A0 return phy_connect_direct(dev, phy, hndlr, flags, iface) ? =
NULL : phy;
> + =A0 =A0 =A0 return phy;
> =A0}
> =A0EXPORT_SYMBOL(of_phy_connect);
> --
> 1.6.3.1
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH 4/4] fs_enet: Revive fixed link support
From: Anton Vorontsov @ 2009-06-26 22:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Li Yang, Andy Fleming, linuxppc-dev
In-Reply-To: <20090626222900.GA14594@oksana.dev.rtsoft.ru>

Since commit aa73832c5a80d6c52c69b18af858d88fa595dd3c ("Rework
fs_enet driver to use of_mdio infrastructure") the fixed-link support
is broken in the fs_enet driver.

This patch fixes the support by removing a check for phy_node, today
of_phy_connect() tries to find fixed PHY if phy_node appears to be
NULL.

Also set netdev parent device via SET_NETDEV_DEV() call, this is needed
so that OF MDIO core could find a node pointer for a device.

Plus, fix "if (IS_ERR(phydev))" check, in case of errors,
of_phy_connect() returns NULL, not ERR_PTR as phy_connect().

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/net/fs_enet/fs_enet-main.c |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index b892c3a..1fea39e 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -754,15 +754,10 @@ static int fs_init_phy(struct net_device *dev)
 	fep->oldlink = 0;
 	fep->oldspeed = 0;
 	fep->oldduplex = -1;
-	if(fep->fpi->phy_node)
-		phydev = of_phy_connect(dev, fep->fpi->phy_node,
-					&fs_adjust_link, 0,
-					PHY_INTERFACE_MODE_MII);
-	else {
-		printk("No phy bus ID specified in BSP code\n");
-		return -EINVAL;
-	}
-	if (IS_ERR(phydev)) {
+
+	phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0,
+				PHY_INTERFACE_MODE_MII);
+	if (!phydev) {
 		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
 		return PTR_ERR(phydev);
 	}
@@ -1005,6 +1000,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev,
 		goto out_free_fpi;
 	}
 
+	SET_NETDEV_DEV(ndev, &ofdev->dev);
 	dev_set_drvdata(&ofdev->dev, ndev);
 
 	fep = netdev_priv(ndev);
-- 
1.6.3.1

^ permalink raw reply related

* [PATCH 3/4] ucc_geth: Revive fixed link support
From: Anton Vorontsov @ 2009-06-26 22:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Li Yang, Andy Fleming, linuxppc-dev
In-Reply-To: <20090626222900.GA14594@oksana.dev.rtsoft.ru>

Since commit 0b9da337dca972e7a4144e298ec3adb8f244d4a4 ("Rework
ucc_geth driver to use of_mdio infrastructure") the fixed-link
support is broken.

This patch fixes the support by removing !ug_info->phy_node check,
today the of_phy_connect() will try to find a fixed PHY if the
phy_node appears to be NULL.

Also, remove an old fixed-link code that we don't use any longer.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/net/ucc_geth.c |   18 +++---------------
 1 files changed, 3 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 40c6eba..2dc83b1 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -1590,9 +1590,6 @@ static int init_phy(struct net_device *dev)
 	priv->oldspeed = 0;
 	priv->oldduplex = -1;
 
-	if (!ug_info->phy_node)
-		return 0;
-
 	phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
 				priv->phy_interface);
 	if (!phydev) {
@@ -3608,9 +3605,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 	struct ucc_geth_private *ugeth = NULL;
 	struct ucc_geth_info *ug_info;
 	struct resource res;
-	struct device_node *phy;
 	int err, ucc_num, max_speed = 0;
-	const u32 *fixed_link;
 	const unsigned int *prop;
 	const char *sprop;
 	const void *mac_addr;
@@ -3708,15 +3703,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 
 	ug_info->uf_info.regs = res.start;
 	ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
-	fixed_link = of_get_property(np, "fixed-link", NULL);
-	if (fixed_link) {
-		phy = NULL;
-	} else {
-		phy = of_parse_phandle(np, "phy-handle", 0);
-		if (phy == NULL)
-			return -ENODEV;
-	}
-	ug_info->phy_node = phy;
+
+	ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
 
 	/* Find the TBI PHY node.  If it's not there, we don't support SGMII */
 	ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -3725,7 +3713,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
 	prop = of_get_property(np, "phy-connection-type", NULL);
 	if (!prop) {
 		/* handle interface property present in old trees */
-		prop = of_get_property(phy, "interface", NULL);
+		prop = of_get_property(ug_info->phy_node, "interface", NULL);
 		if (prop != NULL) {
 			phy_interface = enet_to_phy_interface[*prop];
 			max_speed = enet_to_speed[*prop];
-- 
1.6.3.1

^ permalink raw reply related

* [PATCH 2/4] gianfar: Revive fixed link support
From: Anton Vorontsov @ 2009-06-26 22:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Li Yang, Andy Fleming, linuxppc-dev
In-Reply-To: <20090626222900.GA14594@oksana.dev.rtsoft.ru>

Since commit fe192a49118f5b1272317d60c7930ece4e13ae49 ("Rework gianfar
driver to use of_mdio infrastructure") the fixed-link support is
broken, the driver oopses at init_phy():

  Unable to handle kernel paging request for data at address 0x000000e4
  Faulting instruction address: 0xc01cf298
  Oops: Kernel access of bad area, sig: 11 [#1]
  [...]
  NIP [c01cf298] init_phy+0x80/0xdc
  LR [c01cf250] init_phy+0x38/0xdc
  Call Trace:
  [cf81fe80] [c01d1cf8] gfar_enet_open+0x6c/0x19c
  [cf81fea0] [c024494c] dev_open+0xfc/0x134
  [cf81fec0] [c0242edc] dev_change_flags+0x84/0x1ac
  [cf81fee0] [c0399ee0] ic_open_devs+0x168/0x2d8
  [cf81ff20] [c039b2e8] ip_auto_config+0x90/0x2a4
  [cf81ff60] [c0003884] do_one_initcall+0x34/0x1a8

This patch fixes the oops, and removes phy_node checks (of_phy_connect
call now tries to find fixed PHYs if the phy_node is NULL).

Also, remove an old fixed-link code that we don't use any longer.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/net/gianfar.c |   21 +++++----------------
 1 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4ae1d25..41b2107 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -262,15 +262,6 @@ static int gfar_of_init(struct net_device *dev)
 		priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
 
 	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
-	if (!priv->phy_node) {
-		u32 *fixed_link;
-
-		fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL);
-		if (!fixed_link) {
-			err = -ENODEV;
-			goto err_out;
-		}
-	}
 
 	/* Find the TBI PHY.  If it's not there, we don't support SGMII */
 	priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
@@ -657,13 +648,11 @@ static int init_phy(struct net_device *dev)
 
 	interface = gfar_get_interface(dev);
 
-	if (priv->phy_node) {
-		priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link,
-					      0, interface);
-		if (!priv->phydev) {
-			dev_err(&dev->dev, "error: Could not attach to PHY\n");
-			return -ENODEV;
-		}
+	priv->phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, 0,
+				      interface);
+	if (!priv->phydev) {
+		dev_err(&dev->dev, "could not attach to PHY\n");
+		return -ENODEV;
 	}
 
 	if (interface == PHY_INTERFACE_MODE_SGMII)
-- 
1.6.3.1

^ permalink raw reply related

* [PATCH 1/4] of/mdio: Add fixed link support
From: Anton Vorontsov @ 2009-06-26 22:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Li Yang, Andy Fleming, linuxppc-dev
In-Reply-To: <20090626222900.GA14594@oksana.dev.rtsoft.ru>

Currently the fixed link support is broken for all OF ethernet drivers,
an "OF MDIO rework" removed most of the support. Instead of re-adding
fixed-link stuff to the drivers, add the support to a framework, so we
won't duplicate any code.

With this patch, if a node pointer is NULL, then of_phy_connect() will
try to find ethernet device's node, then will look for fixed-link
property, and if specified, it connects PHY as usual, via bus_id (fixed
link PHYs do not have any device tree nodes associated with them).

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/of/of_mdio.c |   45 +++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index aee967d..cfd876a 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -9,6 +9,10 @@
  * out of the OpenFirmware device tree and using it to populate an mii_bus.
  */
 
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/err.h>
 #include <linux/phy.h>
 #include <linux/of.h>
 #include <linux/of_mdio.h>
@@ -129,11 +133,44 @@ struct phy_device *of_phy_connect(struct net_device *dev,
 				  void (*hndlr)(struct net_device *), u32 flags,
 				  phy_interface_t iface)
 {
-	struct phy_device *phy = of_phy_find_device(phy_np);
+	struct phy_device *phy = NULL;
+
+	if (phy_np) {
+		int ret;
+
+		phy = of_phy_find_device(phy_np);
+		if (!phy)
+			return NULL;
+
+		ret = phy_connect_direct(dev, phy, hndlr, flags, iface);
+		if (ret)
+			return NULL;
+	} else if (dev->dev.parent) {
+		struct device_node *net_np;
+		const u32 *phy_id;
+		char *bus_id;
+		int sz;
+
+		net_np = dev_archdata_get_node(&dev->dev.parent->archdata);
+		if (!net_np)
+			return NULL;
+
+		phy_id = of_get_property(net_np, "fixed-link", &sz);
+		if (!phy_id || sz < sizeof(*phy_id))
+			return NULL;
+
+		bus_id = kasprintf(GFP_KERNEL, PHY_ID_FMT, "0", phy_id[0]);
+		if (!bus_id) {
+			dev_err(&dev->dev, "could not allocate memory\n");
+			return NULL;
+		}
 
-	if (!phy)
-		return NULL;
+		phy = phy_connect(dev, bus_id, hndlr, 0, iface);
+		kfree(bus_id);
+		if (IS_ERR(phy))
+			return NULL;
+	}
 
-	return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
+	return phy;
 }
 EXPORT_SYMBOL(of_phy_connect);
-- 
1.6.3.1

^ permalink raw reply related

* [PATCH 0/4 for 2.6.31] NET: Revive fixed link support
From: Anton Vorontsov @ 2009-06-26 22:29 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Li Yang, Andy Fleming, linuxppc-dev

Hi all,

The fixed link support is broken since The Big OF MDIO Rework,
the rework simply removed most of the code that was needed for
fixed links.

Too bad I didn't notice this earlier, I saw a bunch of patches
on the ml, but unfortunately I didn't look very close presuming
that Grant knew what he was doing. :-) And obviously I didn't
test linux-next on anything that requires a fixed link.

Anyway, here are four patches. The first one adds the fixed link
support to a framework, otherwise we'd duplicate the code across
the drivers (as we did previously), and I tried to keep drivers'
changes minimal.

Patches 2 and 3 are for the drivers that I tested in run-time,
with normal PHYs, and fixed links.

Patch #4 was build-tested, but I believe it should work in
run-time too.


Thanks,

-- 
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Geoff Levand @ 2009-06-26 22:05 UTC (permalink / raw)
  To: Alan Stern; +Cc: linuxppc-dev, USB list, abhishekkumar, bugme-daemon
In-Reply-To: <Pine.LNX.4.44L0.0906261638370.4155-100000@iolanthe.rowland.org>

On 06/26/2009 01:42 PM, Alan Stern wrote:
> On Fri, 26 Jun 2009, Geoff Levand wrote:
> 
>> There is a known but yet unfixed bug for the PS3's EHCI Async Periodic
>> (typically audio recording) device handling.  There are a few related
>> hardware errata that I have not yet implemented driver fixes for that
>> I think are causing it.  
>> 
>> I guess it is the same problem as reported by Abhishek since Andrew's
>> dmesg (http://www.osl.iu.edu/~afriedle/dmesg.txt) shows similar 
>> results.
> 
> Yes, it definitely looks the same.
> 
>> More info is here:
>> 
>>   http://ozlabs.org/pipermail/cbe-oss-dev/2009-February/006365.html
>> 
>> I have bought a ART Tube USB device but have not had time to fix
>> this bug.  It is on my todo list.  Please feel free to make an
>> attempt.
> 
> Where is the information about the hardware errata you mentioned?

Sorry, I should have mentioned it.  Unfortunately, that info is not
in the public as far as I know.  I think only someone with access
to those will be able to work on this fix.

-Geoff

^ permalink raw reply

* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Alan Stern @ 2009-06-26 20:42 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev, USB list, abhishekkumar, bugme-daemon
In-Reply-To: <4A450207.5000502@am.sony.com>

On Fri, 26 Jun 2009, Geoff Levand wrote:

> There is a known but yet unfixed bug for the PS3's EHCI Async Periodic
> (typically audio recording) device handling.  There are a few related
> hardware errata that I have not yet implemented driver fixes for that
> I think are causing it.  
> 
> I guess it is the same problem as reported by Abhishek since Andrew's
> dmesg (http://www.osl.iu.edu/~afriedle/dmesg.txt) shows similar 
> results.

Yes, it definitely looks the same.

> More info is here:
> 
>   http://ozlabs.org/pipermail/cbe-oss-dev/2009-February/006365.html
> 
> I have bought a ART Tube USB device but have not had time to fix
> this bug.  It is on my todo list.  Please feel free to make an
> attempt.

Where is the information about the hardware errata you mentioned?

Alan Stern

^ permalink raw reply

* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Geoff Levand @ 2009-06-26 17:14 UTC (permalink / raw)
  To: Alan Stern; +Cc: linuxppc-dev, USB list, abhishekkumar, bugme-daemon
In-Reply-To: <Pine.LNX.4.44L0.0906261140540.2965-100000@iolanthe.rowland.org>

Hi,

On 06/26/2009 08:54 AM, Alan Stern wrote:
> On Fri, 26 Jun 2009, abhishekkumar wrote:
>>
>> bus ps3_system_bus, device sb_05 (driver 10 Dec 2004)
>> PS3 EHCI Host Controller
>> EHCI ff.ff, hcd state 1
>> structural params 0xffffffff
>> capability params 0xffffffff
>> status ffffffff Async Periodic Recl Halt IAA FATAL FLR PCD ERR INT
>> command ffffffff park=3 ithresh=63 LReset IAAD Async Periodic period=?? Reset R
>> intrenable ffffffff IAA FATAL FLR PCD ERR INT
>> uframe ffffffff
>> port 1 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
>> port 2 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
>> irq normal 30832 err 30 reclaim 84 (lost 1)
>> complete 31221 unlink 10
> 
> This is very bad.  It indicates that the CPU was unable to communicate
> with the EHCI controller at all!  All the memory-mapped I/O reads
> returned 0xffffffff.  No wonder the keyboard and mouse stopped working.
> 
> I have no idea what could have caused this to happen.  Even if the 
> controller had suffered a fatal error, you wouldn't see this.  It looks 
> like the bus's connection to the controller was turned off.
> 
> I'm CC-ing the PS3 maintainer and mailing list.  Maybe people there can 
> help.
> 
> Alan Stern


There is a known but yet unfixed bug for the PS3's EHCI Async Periodic
(typically audio recording) device handling.  There are a few related
hardware errata that I have not yet implemented driver fixes for that
I think are causing it.  

I guess it is the same problem as reported by Abhishek since Andrew's
dmesg (http://www.osl.iu.edu/~afriedle/dmesg.txt) shows similar 
results.

More info is here:

  http://ozlabs.org/pipermail/cbe-oss-dev/2009-February/006365.html

I have bought a ART Tube USB device but have not had time to fix
this bug.  It is on my todo list.  Please feel free to make an
attempt.

Alan, thanks for your effort on this so far, sorry you didn't know
about the previous report.

-Geoff

^ permalink raw reply

* Re: Trouble "Transferring control to Linux (at address 00000000)"
From: Mikhail Zaturenskiy @ 2009-06-26 17:12 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <4A44FD90.2040607@freescale.com>

Hi Scott,

> This isn't the denx list;
I've noticed :) but I'm still learning about this whole process so I
though I could get some general suggestions.

> what kernel version is that, and with what
> modifications from mainline?
Kernel is v2.6.30, I'm not yet familiar enough with it to know what's
been modified from mainline, just following instructions.

> Note that ep88xc.dts in mainline is intended for use with PlanetCore, whi=
ch
> is what ships on that board. =A0You may need to make modifications for it=
 to
> work with u-boot (at the least, the IMMR base is probably different).
Hmm, this hasn't occurred to me, thank you for pointing it out.

> Also, make sure u-boot is properly updating the memory size in the device
> tree. =A0Can you dump the post-fixup device tree in u-boot?
Not sure, but I'll try to find out if that's possible. It'd certainly
answer a lot of questions...

Thanks,
Mikhail Zaturenskiy

^ permalink raw reply

* Re: Trouble "Transferring control to Linux (at address 00000000)"
From: Scott Wood @ 2009-06-26 16:55 UTC (permalink / raw)
  To: Mikhail Zaturenskiy; +Cc: linuxppc-dev
In-Reply-To: <97dd5fd20906260913x351593c9raa429fd657eb42f0@mail.gmail.com>

Mikhail Zaturenskiy wrote:
> Hello,
> 
> I'm trying to load Linux from U-Boot. I am using ELDK 4.2 with U-Boot
> 2009.03 on an EP88xC rev1.1 board (MPC885 cpu, 64MB RAM, 32MB FLASH).
> The linux kernel sources were obtained from instructions at
> "http://www.denx.de/wiki/view/DULG/LinuxConfiguration#Section_6.1."
> and the FDT blob (dtb) was generated from
> "linux-2.6-denx/arch/powerpc/boot/dts/ep88xc.dts". Below is my output
> from boot to hang:

This isn't the denx list; what kernel version is that, and with what 
modifications from mainline?

Note that ep88xc.dts in mainline is intended for use with PlanetCore, which is 
what ships on that board.  You may need to make modifications for it to work 
with u-boot (at the least, the IMMR base is probably different).  This is why 
u-boot should be maintaining its own repository of trees that it passes...

Also, make sure u-boot is properly updating the memory size in the device tree. 
  Can you dump the post-fixup device tree in u-boot?

-Scott

^ permalink raw reply

* Re: [PATCH] sky2: Fix checksum endianness
From: David Miller @ 2009-06-26 16:28 UTC (permalink / raw)
  To: avorontsov; +Cc: netdev, shemminger, linux-kernel, linuxppc-dev
In-Reply-To: <20090626145159.GA2242@oksana.dev.rtsoft.ru>

From: Anton Vorontsov <avorontsov@ru.mvista.com>
Date: Fri, 26 Jun 2009 18:51:59 +0400

> sky2 driver on PowerPC targets floods kernel log with following errors:
> 
>   eth1: hw csum failure.
>   Call Trace:
>   [ef84b8a0] [c00075e4] show_stack+0x50/0x160 (unreliable)
>   [ef84b8d0] [c02fa178] netdev_rx_csum_fault+0x3c/0x5c
>   [ef84b8f0] [c02f6920] __skb_checksum_complete_head+0x7c/0x84
>   [ef84b900] [c02f693c] __skb_checksum_complete+0x14/0x24
>   [ef84b910] [c0337e08] tcp_v4_rcv+0x4c8/0x6f8
>   [ef84b940] [c031a9c8] ip_local_deliver+0x98/0x210
>   [ef84b960] [c031a788] ip_rcv+0x38c/0x534
>   [ef84b990] [c0300338] netif_receive_skb+0x260/0x36c
>   [ef84b9c0] [c025de00] sky2_poll+0x5dc/0xcf8
>   [ef84ba20] [c02fb7fc] net_rx_action+0xc0/0x144
> 
> The NIC is Yukon-2 EC chip revision 1.
> 
> Converting checksum field from le16 to CPU byte order fixes the issue.
> 
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>

Applied, thank you!

^ permalink raw reply

* Subject: [PATCH v8] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-26 16:24 UTC (permalink / raw)
  To: David Brownell, Stefan Roese, linuxppc-dev@ozlabs.org

This adds a SPI driver for the SPI controller found in the IBM/AMCC
4xx PowerPC's.

Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Wolfgang Ocker <weo@reccoware.de>
Acked-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Signed-off-by: Steven A. Falco <sfalco@harris.com>
---
Changes in v8:
- Removed redundant dbg messages
- Using new master->mode_line variable
- Removed redundant test and assignment of bits_per_word
- Some white-space fixes from checkpatch

Changes in v7:
- Additional comments as per David Brownell's review
- Corrected phase in mode 2 and 3
- Corrected speed and bits_per_word logic in spi_ppc4xx_setupxfer
- Removed extraneous tests as per David's review
- Added support for "holes" in the chip-select list
- Using dynamic bus allocation
- Corrected initialization logic

Changes in v6:
- Moved comment about high interrupt load to top of file and extended it
  by explaining that the 4xx SPI controller has no FIFOs.
- Added parameter checking to setup() routine.
- Removed comment about LSB
- Used of_gpio_count() instead creating own static implementation as
  suggested by Anton.

Changes in v5:
- Don't call setupxfer() from setup() so that the baudrate etc
  won't get changed while another transfer is active, as suggested
  by David Brownell.
- module_{init,exit} moved directly to the functions to which they
  apply.
- Use __func__ instead of __FUNCTION__.

Changes in v4:
- Added fixes suggested by Josh Boyer
- Changed compatible property from "ibm,spi" to "ibm,ppc4xx-spi"

Changes in v3:
- When the device is removed the GPIOs are released. The memory
  for the GPIO array is freed.

Changes in v2:
- Now the gpios property is correctly decoded and the
  resulting gpio numbers are used as the devices chip
  selects.

 drivers/spi/Kconfig      |    7 +
 drivers/spi/Makefile     |    1 +
 drivers/spi/spi_ppc4xx.c |  612 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 620 insertions(+), 0 deletions(-)
 create mode 100644 drivers/spi/spi_ppc4xx.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 2c733c2..1dd9f94 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -178,6 +178,13 @@ config SPI_PL022
 	  controller. If you have an embedded system with an AMBA(R)
 	  bus and a PL022 controller, say Y or M here.
 
+config SPI_PPC4xx
+	tristate "PPC4xx SPI Controller"
+	depends on 4xx && SPI_MASTER
+	select SPI_BITBANG
+	help
+	  This selects a driver for the PPC4xx SPI Controller.
+
 config SPI_PXA2XX
 	tristate "PXA2xx SSP SPI master"
 	depends on ARCH_PXA && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3de408d..cc9a420 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_ORION)			+= orion_spi.o
 obj-$(CONFIG_SPI_PL022)			+= amba-pl022.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC8xxx)		+= spi_mpc8xxx.o
+obj-$(CONFIG_SPI_PPC4xx)		+= spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
 obj-$(CONFIG_SPI_TXX9)			+= spi_txx9.o
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
new file mode 100644
index 0000000..140a18d
--- /dev/null
+++ b/drivers/spi/spi_ppc4xx.c
@@ -0,0 +1,612 @@
+/*
+ * SPI_PPC4XX SPI controller driver.
+ *
+ * Copyright (C) 2007 Gary Jennejohn <garyj@denx.de>
+ * Copyright 2008 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ * Copyright 2009 Harris Corporation, Steven A. Falco <sfalco@harris.com>
+ *
+ * Based in part on drivers/spi/spi_s3c24xx.c
+ *
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * The PPC4xx SPI controller has no FIFO so each sent/received byte will
+ * generate an interrupt to the CPU. This can cause high CPU utilization.
+ * This driver allows platforms to reduce the interrupt load on the CPU
+ * during SPI transfers by setting max_speed_hz via the device tree.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/io.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+
+/* bits in mode register - bit 0 is MSb */
+
+/*
+ * SPI_PPC4XX_MODE_SCP = 0 means "data latched on trailing edge of clock"
+ * SPI_PPC4XX_MODE_SCP = 1 means "data latched on leading edge of clock"
+ * Note: This is the inverse of CPHA.
+ */
+#define SPI_PPC4XX_MODE_SCP	(0x80 >> 3)
+
+/* SPI_PPC4XX_MODE_SPE = 1 means "port enabled" */
+#define SPI_PPC4XX_MODE_SPE	(0x80 >> 4)
+
+/*
+ * SPI_PPC4XX_MODE_RD = 0 means "MSB first" - this is the normal mode
+ * SPI_PPC4XX_MODE_RD = 1 means "LSB first" - this is bit-reversed mode
+ * Note: This is identical to SPI_LSB_FIRST.
+ */
+#define SPI_PPC4XX_MODE_RD	(0x80 >> 5)
+
+/*
+ * SPI_PPC4XX_MODE_CI = 0 means "clock idles low"
+ * SPI_PPC4XX_MODE_CI = 1 means "clock idles high"
+ * Note: This is identical to CPOL.
+ */
+#define SPI_PPC4XX_MODE_CI	(0x80 >> 6)
+
+/*
+ * SPI_PPC4XX_MODE_IL = 0 means "loopback disable"
+ * SPI_PPC4XX_MODE_IL = 1 means "loopback enable"
+ */
+#define SPI_PPC4XX_MODE_IL	(0x80 >> 7)
+
+/* bits in control register */
+/* starts a transfer when set */
+#define SPI_PPC4XX_CR_STR	(0x80 >> 7)
+
+/* bits in status register */
+/* port is busy with a transfer */
+#define SPI_PPC4XX_SR_BSY	(0x80 >> 6)
+/* RxD ready */
+#define SPI_PPC4XX_SR_RBR	(0x80 >> 7)
+
+/* clock settings (SCP and CI) for various SPI modes */
+#define SPI_CLK_MODE0	(SPI_PPC4XX_MODE_SCP | 0)
+#define SPI_CLK_MODE1	(0 | 0)
+#define SPI_CLK_MODE2	(SPI_PPC4XX_MODE_SCP | SPI_PPC4XX_MODE_CI)
+#define SPI_CLK_MODE3	(0 | SPI_PPC4XX_MODE_CI)
+
+#define DRIVER_NAME	"spi_ppc4xx_of"
+
+struct spi_ppc4xx_regs {
+	u8 mode;
+	u8 rxd;
+	u8 txd;
+	u8 cr;
+	u8 sr;
+	u8 dummy;
+	/*
+	 * Clock divisor modulus register
+	 * This uses the follwing formula:
+	 *    SCPClkOut = OPBCLK/(4(CDM + 1))
+	 * or
+	 *    CDM = (OPBCLK/4*SCPClkOut) - 1
+	 * bit 0 is the MSb!
+	 */
+	u8 cdm;
+};
+
+/* SPI Controller driver's private data. */
+struct ppc4xx_spi {
+	/* bitbang has to be first */
+	struct spi_bitbang bitbang;
+	struct completion done;
+
+	u64 mapbase;
+	u64 mapsize;
+	int irqnum;
+	/* need this to set the SPI clock */
+	unsigned int opb_freq;
+
+	/* for transfers */
+	int len;
+	int count;
+	/* data buffers */
+	const unsigned char *tx;
+	unsigned char *rx;
+
+	int *gpios;
+
+	struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
+	struct spi_master *master;
+	struct device *dev;
+};
+
+/* need this so we can set the clock in the chipselect routine */
+struct spi_ppc4xx_cs {
+	u8 mode;
+};
+
+static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct ppc4xx_spi *hw;
+	u8 data;
+
+	dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
+		t->tx_buf, t->rx_buf, t->len);
+
+	hw = spi_master_get_devdata(spi->master);
+
+	hw->tx = t->tx_buf;
+	hw->rx = t->rx_buf;
+	hw->len = t->len;
+	hw->count = 0;
+
+	/* send the first byte */
+	data = hw->tx ? hw->tx[0] : 0;
+	out_8(&hw->regs->txd, data);
+	out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+	wait_for_completion(&hw->done);
+
+	return hw->count;
+}
+
+static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+	struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+	struct spi_ppc4xx_cs *cs = spi->controller_state;
+	int scr;
+	u8 cdm = 0;
+	u32 speed;
+	u8 bits_per_word;
+
+	/* Start with the generic configuration for this device. */
+	bits_per_word = spi->bits_per_word;
+	speed = spi->max_speed_hz;
+
+	/*
+	 * Modify the configuration if the transfer overrides it.  Do not allow
+	 * the transfer to overwrite the generic configuration with zeros.
+	 */
+	if (t) {
+		if (t->bits_per_word)
+			bits_per_word = t->bits_per_word;
+
+		if (t->speed_hz)
+			speed = min(t->speed_hz, spi->max_speed_hz);
+	}
+
+	if (bits_per_word != 8) {
+		dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
+				bits_per_word);
+		return -EINVAL;
+	}
+
+	if (!speed || (speed > spi->max_speed_hz)) {
+		dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
+		return -EINVAL;
+	}
+
+	/* Write new configration */
+	out_8(&hw->regs->mode, cs->mode);
+
+	/* Set the clock */
+	/* opb_freq was already divided by 4 */
+	scr = (hw->opb_freq / speed) - 1;
+	if (scr > 0)
+		cdm = min(scr, 0xff);
+
+	dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", cdm, speed);
+
+	if (in_8(&hw->regs->cdm) != cdm)
+		out_8(&hw->regs->cdm, cdm);
+
+	spin_lock(&hw->bitbang.lock);
+	if (!hw->bitbang.busy) {
+		hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
+		/* Need to ndelay here? */
+	}
+	spin_unlock(&hw->bitbang.lock);
+
+	return 0;
+}
+
+static int spi_ppc4xx_setup(struct spi_device *spi)
+{
+	struct spi_ppc4xx_cs *cs = spi->controller_state;
+
+	if (spi->bits_per_word != 8) {
+		dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
+			spi->bits_per_word);
+		return -EINVAL;
+	}
+
+	if (!spi->max_speed_hz) {
+		dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
+		return -EINVAL;
+	}
+
+	if (cs == NULL) {
+		cs = kzalloc(sizeof *cs, GFP_KERNEL);
+		if (!cs)
+			return -ENOMEM;
+		spi->controller_state = cs;
+	}
+
+	/*
+	 * We set all bits of the SPI0_MODE register, so,
+	 * no need to read-modify-write
+	 */
+	cs->mode = SPI_PPC4XX_MODE_SPE;
+
+	switch (spi->mode & (SPI_CPHA | SPI_CPOL)) {
+	case SPI_MODE_0:
+		cs->mode |= SPI_CLK_MODE0;
+		break;
+	case SPI_MODE_1:
+		cs->mode |= SPI_CLK_MODE1;
+		break;
+	case SPI_MODE_2:
+		cs->mode |= SPI_CLK_MODE2;
+		break;
+	case SPI_MODE_3:
+		cs->mode |= SPI_CLK_MODE3;
+		break;
+	}
+
+	if (spi->mode & SPI_LSB_FIRST)
+		cs->mode |= SPI_PPC4XX_MODE_RD;
+
+	return 0;
+}
+
+static void spi_ppc4xx_chipsel(struct spi_device *spi, int value)
+{
+	struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+	unsigned int cs = spi->chip_select;
+	unsigned int cspol;
+
+	/*
+	 * If there are no chip selects at all, or if this is the special
+	 * case of a non-existent (dummy) chip select, do nothing.
+	 */
+
+	if (!hw->master->num_chipselect || hw->gpios[cs] == -EEXIST)
+		return;
+
+	cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+	if (value == BITBANG_CS_INACTIVE)
+		cspol = !cspol;
+
+	gpio_set_value(hw->gpios[cs], cspol);
+}
+
+static irqreturn_t spi_ppc4xx_int(int irq, void *dev_id)
+{
+	struct ppc4xx_spi *hw;
+	u8 status;
+	u8 data;
+	unsigned int count;
+
+	hw = (struct ppc4xx_spi *)dev_id;
+
+	status = in_8(&hw->regs->sr);
+	if (!status)
+		return IRQ_NONE;
+
+	/*
+	 * BSY de-asserts one cycle after the transfer is complete.  The
+	 * interrupt is asserted after the transfer is complete.  The exact
+	 * relationship is not documented, hence this code.
+	 */
+
+	if (unlikely(status & SPI_PPC4XX_SR_BSY)) {
+		u8 lstatus;
+		int cnt = 0;
+
+		dev_dbg(hw->dev, "got interrupt but spi still busy?\n");
+		do {
+			ndelay(10);
+			lstatus = in_8(&hw->regs->sr);
+		} while (++cnt < 100 && lstatus & SPI_PPC4XX_SR_BSY);
+
+		if (cnt >= 100) {
+			dev_err(hw->dev, "busywait: too many loops!\n");
+			complete(&hw->done);
+			return IRQ_HANDLED;
+		} else {
+			/* status is always 1 (RBR) here */
+			status = in_8(&hw->regs->sr);
+			dev_dbg(hw->dev, "loops %d status %x\n", cnt, status);
+		}
+	}
+
+	count = hw->count;
+	hw->count++;
+
+	/* RBR triggered this interrupt.  Therefore, data must be ready. */
+	data = in_8(&hw->regs->rxd);
+	if (hw->rx)
+		hw->rx[count] = data;
+
+	count++;
+
+	if (count < hw->len) {
+		data = hw->tx ? hw->tx[count] : 0;
+		out_8(&hw->regs->txd, data);
+		out_8(&hw->regs->cr, SPI_PPC4XX_CR_STR);
+	} else {
+		complete(&hw->done);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void spi_ppc4xx_cleanup(struct spi_device *spi)
+{
+	kfree(spi->controller_state);
+}
+
+static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
+{
+	/*
+	 * On all 4xx PPC's the SPI bus is shared/multiplexed with
+	 * the 2nd I2C bus. We need to enable the the SPI bus before
+	 * using it.
+	 */
+
+	/* need to clear bit 14 to enable SPC */
+	dcri_clrset(SDR0, SDR0_PFC1, 0x80000000 >> 14, 0);
+}
+
+static void free_gpios(struct ppc4xx_spi *hw)
+{
+	if (hw->master->num_chipselect) {
+		int i;
+		for (i = 0; i < hw->master->num_chipselect; i++)
+			if (gpio_is_valid(hw->gpios[i]))
+				gpio_free(hw->gpios[i]);
+
+		kfree(hw->gpios);
+		hw->gpios = NULL;
+	}
+}
+
+/*
+ * of_device layer stuff...
+ */
+static int __init spi_ppc4xx_of_probe(struct of_device *op,
+				      const struct of_device_id *match)
+{
+	struct ppc4xx_spi *hw;
+	struct spi_master *master;
+	struct spi_bitbang *bbp;
+	struct resource resource;
+	struct device_node *np = op->node;
+	struct device *dev = &op->dev;
+	struct device_node *opbnp;
+	int ret;
+	int num_gpios;
+	const unsigned int *clk;
+
+	master = spi_alloc_master(dev, sizeof *hw);
+	if (master == NULL)
+		return -ENOMEM;
+	dev_set_drvdata(dev, master);
+	hw = spi_master_get_devdata(master);
+	hw->master = spi_master_get(master);
+	hw->dev = dev;
+
+	init_completion(&hw->done);
+
+	/*
+	 * A count of zero implies a single SPI device without any chip-select.
+	 * Note that of_gpio_count counts all gpios assigned to this spi master.
+	 * This includes both "null" gpio's and real ones.
+	 */
+	num_gpios = of_gpio_count(np);
+	if (num_gpios) {
+		int i;
+
+		hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL);
+		if (!hw->gpios) {
+			ret = -ENOMEM;
+			goto free_master;
+		}
+
+		for (i = 0; i < num_gpios; i++) {
+			int gpio;
+			enum of_gpio_flags flags;
+
+			gpio = of_get_gpio_flags(np, i, &flags);
+			hw->gpios[i] = gpio;
+
+			if (gpio_is_valid(gpio)) {
+				/* Real CS - set the initial state. */
+				ret = gpio_request(gpio, np->name);
+				if (ret < 0) {
+					dev_err(dev, "can't request gpio "
+							"#%d: %d\n", i, ret);
+					goto free_gpios;
+				}
+
+				gpio_direction_output(gpio,
+						!!(flags & OF_GPIO_ACTIVE_LOW));
+			} else if (gpio == -EEXIST) {
+				; /* No CS, but that's OK. */
+			} else {
+				dev_err(dev, "invalid gpio #%d: %d\n", i, gpio);
+				ret = -EINVAL;
+				goto free_gpios;
+			}
+		}
+	}
+
+	/* Setup the state for the bitbang driver */
+	bbp = &hw->bitbang;
+	bbp->master = hw->master;
+	bbp->setup_transfer = spi_ppc4xx_setupxfer;
+	bbp->chipselect = spi_ppc4xx_chipsel;
+	bbp->txrx_bufs = spi_ppc4xx_txrx;
+	bbp->use_dma = 0;
+	bbp->master->setup = spi_ppc4xx_setup;
+	bbp->master->cleanup = spi_ppc4xx_cleanup;
+
+	/* Allocate bus num dynamically. */
+	bbp->master->bus_num = -1;
+
+	/* the spi->mode bits understood by this driver: */
+	bbp->master->mode_bits =
+		SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
+
+	/* this many pins in all GPIO controllers */
+	bbp->master->num_chipselect = num_gpios;
+
+	/* Get the clock for the OPB */
+	opbnp = of_find_compatible_node(NULL, NULL, "ibm,opb");
+	if (opbnp == NULL) {
+		dev_err(dev, "OPB: cannot find node\n");
+		ret = -ENODEV;
+		goto free_gpios;
+	}
+	/* Get the clock (Hz) for the OPB */
+	clk = of_get_property(opbnp, "clock-frequency", NULL);
+	if (clk == NULL) {
+		dev_err(dev, "OPB: no clock-frequency property set\n");
+		of_node_put(opbnp);
+		ret = -ENODEV;
+		goto free_gpios;
+	}
+	hw->opb_freq = *clk;
+	hw->opb_freq >>= 2;
+	of_node_put(opbnp);
+
+	ret = of_address_to_resource(np, 0, &resource);
+	if (ret) {
+		dev_err(dev, "error while parsing device node resource\n");
+		goto free_gpios;
+	}
+	hw->mapbase = resource.start;
+	hw->mapsize = resource.end - resource.start + 1;
+
+	/* Sanity check */
+	if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
+		dev_err(dev, "too small to map registers\n");
+		ret = -EINVAL;
+		goto free_gpios;
+	}
+
+	/* Request IRQ */
+	hw->irqnum = irq_of_parse_and_map(np, 0);
+	ret = request_irq(hw->irqnum, spi_ppc4xx_int,
+			  IRQF_DISABLED, "spi_ppc4xx_of", (void *)hw);
+	if (ret) {
+		dev_err(dev, "unable to allocate interrupt\n");
+		goto free_gpios;
+	}
+
+	if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
+		dev_err(dev, "resource unavailable\n");
+		ret = -EBUSY;
+		goto request_mem_error;
+	}
+
+	hw->regs = ioremap(hw->mapbase, sizeof(struct spi_ppc4xx_regs));
+
+	if (!hw->regs) {
+		dev_err(dev, "unable to memory map registers\n");
+		ret = -ENXIO;
+		goto map_io_error;
+	}
+
+	spi_ppc4xx_enable(hw);
+
+	/* Finally register our spi controller */
+	dev->dma_mask = 0;
+	ret = spi_bitbang_start(bbp);
+	if (ret) {
+		dev_err(dev, "failed to register SPI master\n");
+		goto unmap_regs;
+	}
+
+	dev_info(dev, "driver initialized\n");
+	of_register_spi_devices(master, np);
+
+	return 0;
+
+unmap_regs:
+	iounmap(hw->regs);
+map_io_error:
+	release_mem_region(hw->mapbase, hw->mapsize);
+request_mem_error:
+	free_irq(hw->irqnum, hw);
+free_gpios:
+	free_gpios(hw);
+free_master:
+	dev_set_drvdata(dev, NULL);
+	spi_master_put(master);
+
+	dev_err(dev, "initialization failed\n");
+	return ret;
+}
+
+static int __exit spi_ppc4xx_of_remove(struct of_device *op)
+{
+	struct spi_master *master = dev_get_drvdata(&op->dev);
+	struct ppc4xx_spi *hw = spi_master_get_devdata(master);
+
+	spi_bitbang_stop(&hw->bitbang);
+	dev_set_drvdata(&op->dev, NULL);
+	release_mem_region(hw->mapbase, hw->mapsize);
+	free_irq(hw->irqnum, hw);
+	iounmap(hw->regs);
+	free_gpios(hw);
+	return 0;
+}
+
+static struct of_device_id spi_ppc4xx_of_match[] = {
+	{ .compatible = "ibm,ppc4xx-spi", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
+
+static struct of_platform_driver spi_ppc4xx_of_driver = {
+	.match_table = spi_ppc4xx_of_match,
+	.probe = spi_ppc4xx_of_probe,
+	.remove = __exit_p(spi_ppc4xx_of_remove),
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init spi_ppc4xx_init(void)
+{
+	return of_register_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_init(spi_ppc4xx_init);
+
+static void __exit spi_ppc4xx_exit(void)
+{
+	of_unregister_platform_driver(&spi_ppc4xx_of_driver);
+}
+module_exit(spi_ppc4xx_exit);
+
+MODULE_AUTHOR("Gary Jennejohn & Stefan Roese");
+MODULE_DESCRIPTION("Simple PPC4xx SPI Driver");
+MODULE_LICENSE("GPL");
-- 
1.6.0.2

^ permalink raw reply related

* Re: Subject: [PATCH v7] spi: Add PPC4xx SPI driver
From: Steven A. Falco @ 2009-06-26 16:17 UTC (permalink / raw)
  Cc: linuxppc-dev@ozlabs.org, Stefan Roese
In-Reply-To: <200906252104.46189.david-b@pacbell.net>

David Brownell wrote:
> On Thursday 25 June 2009, Steven A. Falco wrote:
>> +       if (spi->mode & ~MODEBITS) {
>> +               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
>> +                       spi->mode & ~MODEBITS);
>> +               return -EINVAL;
>> +       }
> 
> This wasn't tested against 2.6.30-rc1 was it?
> 

I tested against Ben's "next" branch, plus your fix for bitbang_work.
But the new version I'll post is tested against Linus' master branch
(2.6.31-rc1) to take advantage of your mode_bits addition.  If you need
this driver to be based on something else, please say so.

> See the recent fixup patch I sent.  There's a spi_master->modebits
> mask that should have been initialized, and which eliminates the
> need for tests like that ...
> 

Done.

>> +       dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
>> +               __func__, spi->mode, spi->bits_per_word,
>> +               spi->max_speed_hz);
>> +
> 
> ... also the SPI core now provides a *standard* format debug
> message for that stuff.  It also handles one more thing, which
> I expect to see fixed in a v8 of this patch ...  :) 

Ok - I removed that dev_dbg().  Also, I noticed that spi_setup sets
bits_per_word to 8, so I've removed that as well.  Did I pass your
test?  :-) 

Version 8 will follow shortly.  BTW, this driver is dependent on your
bitbang_work fix.  Not sure if that means it should be added via your
tree.  But since we are in an rc phase, I'm guessing this won't merge
until 2.6.32, by which time your fix should be in the mainline.

	Steve

^ permalink raw reply

* Trouble "Transferring control to Linux (at address 00000000)"
From: Mikhail Zaturenskiy @ 2009-06-26 16:13 UTC (permalink / raw)
  To: linuxppc-dev

Hello,

I'm trying to load Linux from U-Boot. I am using ELDK 4.2 with U-Boot
2009.03 on an EP88xC rev1.1 board (MPC885 cpu, 64MB RAM, 32MB FLASH).
The linux kernel sources were obtained from instructions at
"http://www.denx.de/wiki/view/DULG/LinuxConfiguration#Section_6.1."
and the FDT blob (dtb) was generated from
"linux-2.6-denx/arch/powerpc/boot/dts/ep88xc.dts". Below is my output
from boot to hang:

U-Boot 2009.03-svn8591 (Jun 25 2009 - 11:08:09)

CPU:   MPC885ZPnn at 100 MHz [40.0...133.0 MHz]
       8 kB I-Cache 8 kB D-Cache FEC present
clock 100000000Hz != 300000Hz
Board: EP88xC 1.1  CPLD revision 2
DRAM:  64 MB
Top of RAM usable for U-Boot at: 04000000
Reserving 208k for U-Boot at: 03fcb000
Reserving 384k for malloc() at: 03f6b000
Reserving 60 Bytes for Board Info at: 03f6afc4
Reserving 56 Bytes for Global Data at: 03f6af8c
Stack Pointer at: 03f6af68
New Stack Pointer is: 03f6af68
Now running in RAM - U-Boot at: 03fcb000
FLASH: flash detect cfi
fwc addr fc000000 cmd f0 f0 8bit x 8 bit
...
... <some output skipped> ...
...
is= cmd 59(Y) addr fc000048 is= 00590059 00590059
device interface is 2
found port 4 chip 2 port 32 bits chip 16 bits
00 : 51 52 59 02 00 40 00 00 00 00 00 27 36 00 00 07  QRY..@.....'6...
...
... <some output skipped> ...
...
fwc addr fc000154 cmd 98 00980098 32bit x 16 bit
manufacturer is 2
manufacturer id is 0x1
device id is 0x227e
device id2 is 0x0
cfi version is 0x3133
size_ratio 2 port 32 bits chip 16 bits
found 1 erase regions
erase region 0: 0x0200007f
erase_region_count = 128 erase_region_size = 131072
fwc addr fc000000 cmd f0 00f000f0 32bit x 16 bit
flash_protect ON: from 0xFC000000 to 0xFC02DFFF
protect on 0
flash_protect ON: from 0xFC040000 to 0xFC07FFFF
protect on 1
32 MB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
U-Boot relocated to 03fcb000
Net:   FEC ETHERNET, FEC2 ETHERNET
### main_loop entered: bootdelay=2

### main_loop: bootcmd="bootm fc080000"
Hit any key to stop autoboot:  0
## Current stack ends at 0x03f6ad50
*  kernel: cmdline image address = 0xfc080000
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=> setenv ipaddr 10.0.54.150
=> setenv serverip 10.0.54.129
=> setenv bootargs root=/dev/ram0 rw
=> setenv ethaddr 00-e0-86-0c-84-fd
eth_set_enetaddr(num=0, addr=00-e0-86-0c-84-fd)
Setting new HW address on FEC ETHERNET
New Address is             00:E0:86:0C:84:FD
eth_set_enetaddr(num=0, addr=00-e0-86-0c-84-fd)
Setting new HW address on FEC ETHERNET
New Address is             00:E0:86:0C:84:FD
=> tftp 400000 ep88x_uimage2
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_uimage2'.
Load address: 0x400000
Loading: #################################################################
         ########
done
Bytes transferred = 1061544 (1032a8 hex)
=> tftp 550000 ep88x_ramdisk3
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_ramdisk3'.
Load address: 0x550000
Loading: #################################################################
         #############################################################
done
Bytes transferred = 1846099 (1c2b53 hex)
=> tftp 750000 ep88x_dtb
Trying FEC ETHERNET
Using FEC ETHERNET device
TFTP from server 10.0.54.129; our IP address is 10.0.54.150
Filename 'ep88x_dtb'.
Load address: 0x750000
Loading: #
done
Bytes transferred = 12288 (3000 hex)
=> bootm 400000 550000 750000
## Current stack ends at 0x03f6ad60
*  kernel: cmdline image address = 0x00400000
## Booting kernel from Legacy Image at 00400000 ...
   Image Name:   Linux-2.6.30-rc2-01402-gd4e2f68-
   Image Type:   PowerPC Linux Kernel Image (gzip compressed)
   Data Size:    1061480 Bytes =  1 MB
   Load Address: 00000000
   Entry Point:  00000000
   Entry Point:  00000000
   kernel data at 0x00400040, len = 0x00103268 (1061480)
*  ramdisk: cmdline image address = 0x00550000
## Loading init Ramdisk from Legacy Image at 00550000 ...
   Image Name:   Simple Embedded Linux Framework
   Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
   Data Size:    1846035 Bytes =  1.8 MB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   ramdisk start = 0x00550040, ramdisk end = 0x00712b53
*  fdt: cmdline image address = 0x00750000
## Checking for 'FDT'/'FDT Image' at 00750000
*  fdt: raw FDT blob
## Flattened Device Tree blob at 00750000
   Booting using the fdt blob at 0x750000
   of_flat_tree at 0x00750000 size 0x00003000
   Uncompressing Kernel Image ... OK
   kernel loaded at 0x00000000, end = 0x00226224
## initrd_high = 0xffffffff, copy_to_ram = 1
   Loading Ramdisk to 03da7000, end 03f69b13 ... OK
   ramdisk load start = 0x03da7000, ramdisk load end = 0x03f69b13
## Transferring control to Linux (at address 00000000) ...
   Booting using OF flat tree...

I did a post-mortem analysis
(http://www.denx.de/wiki/view/DULG/LinuxPostMortemAnalysis) and came
up with the following message:
<6>Using Embedded Planet EP88xC machine description.
<0>Kernel panic - not syncing: Error: Failed to allocate 0x1
................0x800000..
<0>.
<4>Call Trace:.
<4>................69e0]
show_stack...............................21f00] [c001bcb4]
panic+0x8c/0x1................ [c01fac70] lmb_alloc+0x0/0xc.
<4>[c0221f70] [c01................_page+0x60/0x74.
<4>[c0221f80] [c01a4484] pte_alloc_one_kernel+0x

I'm not quite sure where to go from here to get linux working. Anybody
have any suggestions?

Thank you,
Mikhail Zaturenskiy

^ permalink raw reply

* Re: [Bugme-new] [Bug 13304] New: ehci_hcd module causing problems in using usb head phone
From: Alan Stern @ 2009-06-26 15:54 UTC (permalink / raw)
  To: abhishekkumar; +Cc: linuxppc-dev, USB list, bugme-daemon
In-Reply-To: <4A44CB89.8040802@tataelxsi.co.in>

On Fri, 26 Jun 2009, abhishekkumar wrote:

> PFA I am attaching dmesg file taken from /var/log/ and also the lines 
> which I got from dmesg command in different file named dmesgafter.txt.

I still don't see any lines about the headphone device in the log.  
Was the headphone plugged in during boot, or did you plug it in later?

> Then , periodic and registers files and also the usbmon log.

Here's what your "registers" file says:

> bus ps3_system_bus, device sb_05 (driver 10 Dec 2004)
> PS3 EHCI Host Controller
> EHCI ff.ff, hcd state 1
> structural params 0xffffffff
> capability params 0xffffffff
> status ffffffff Async Periodic Recl Halt IAA FATAL FLR PCD ERR INT
> command ffffffff park=3 ithresh=63 LReset IAAD Async Periodic period=?? Reset R
> intrenable ffffffff IAA FATAL FLR PCD ERR INT
> uframe ffffffff
> port 1 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
> port 2 status ffffffff POWER OWNER sig=? RESET SUSPEND RESUME OCC OC PEC PE CSC
> irq normal 30832 err 30 reclaim 84 (lost 1)
> complete 31221 unlink 10

This is very bad.  It indicates that the CPU was unable to communicate
with the EHCI controller at all!  All the memory-mapped I/O reads
returned 0xffffffff.  No wonder the keyboard and mouse stopped working.

I have no idea what could have caused this to happen.  Even if the 
controller had suffered a fatal error, you wouldn't see this.  It looks 
like the bus's connection to the controller was turned off.

I'm CC-ing the PS3 maintainer and mailing list.  Maybe people there can 
help.

> I am even not able to kill the application because it's not showing when 
> I use top command.
> 
> I addition to that I get some messages during boot up . they are
> Unable to  accept address for port 1 (error -62)
> usb cable may be bad
> Unable to  accept address for port 2 (error -62)

Those are normal.  They occur because your system loads ohci-hcd before 
ehci-hcd.  It should load ehci-hcd first.

Alan Stern

^ permalink raw reply

* [PATCH] sky2: Fix checksum endianness
From: Anton Vorontsov @ 2009-06-26 14:51 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Stephen Hemminger, linux-kernel, linuxppc-dev

sky2 driver on PowerPC targets floods kernel log with following errors:

  eth1: hw csum failure.
  Call Trace:
  [ef84b8a0] [c00075e4] show_stack+0x50/0x160 (unreliable)
  [ef84b8d0] [c02fa178] netdev_rx_csum_fault+0x3c/0x5c
  [ef84b8f0] [c02f6920] __skb_checksum_complete_head+0x7c/0x84
  [ef84b900] [c02f693c] __skb_checksum_complete+0x14/0x24
  [ef84b910] [c0337e08] tcp_v4_rcv+0x4c8/0x6f8
  [ef84b940] [c031a9c8] ip_local_deliver+0x98/0x210
  [ef84b960] [c031a788] ip_rcv+0x38c/0x534
  [ef84b990] [c0300338] netif_receive_skb+0x260/0x36c
  [ef84b9c0] [c025de00] sky2_poll+0x5dc/0xcf8
  [ef84ba20] [c02fb7fc] net_rx_action+0xc0/0x144

The NIC is Yukon-2 EC chip revision 1.

Converting checksum field from le16 to CPU byte order fixes the issue.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 drivers/net/sky2.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7681d28..daf961a 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -2495,7 +2495,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 			if (likely(status >> 16 == (status & 0xffff))) {
 				skb = sky2->rx_ring[sky2->rx_next].skb;
 				skb->ip_summed = CHECKSUM_COMPLETE;
-				skb->csum = status & 0xffff;
+				skb->csum = le16_to_cpu(status);
 			} else {
 				printk(KERN_NOTICE PFX "%s: hardware receive "
 				       "checksum problem (status = %#x)\n",
-- 
1.6.3.1

^ permalink raw reply related

* [PATCH] Remove 'SBC8240 Wind River' Device Driver Code
From: Subrata Modak @ 2009-06-26 14:25 UTC (permalink / raw)
  To: Scott Wood, David Woodhouse
  Cc: carolyn.j.smith, Stephen Rothwell, Adrian Bunk, Jim Cromie,
	linux-kernel, Linuxppc-dev, Sachin P Sant, linux-next,
	Subrata Modak, Alexander Beregalov, Balbir Singh

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 10601 bytes --]

Hi David/Scott,

Today's next tree(20090626) produced the following build error:

CC [M]  drivers/mtd/maps/sbc8240.o
drivers/mtd/maps/sbc8240.c:31:1: warning: "DEBUG" redefined
In file included from drivers/mtd/maps/sbc8240.c:23:
include/linux/mtd/mtd.h:333:1: warning: this is the location of the previous definition
drivers/mtd/maps/sbc8240.c: In function 'init_sbc8240_mtd':
drivers/mtd/maps/sbc8240.c:172: warning: passing argument 1 of 'simple_map_init' from incompatible pointer type
drivers/mtd/maps/sbc8240.c:177: error: 'struct mtd_info' has no member named 'module'
make[3]: *** [drivers/mtd/maps/sbc8240.o] Error 1
make[2]: *** [drivers/mtd/maps] Error 2
make[1]: *** [drivers/mtd] Error 2
make: *** [drivers] Error 2

I remember reporting this log back in April, when you suggested in removing it:
http://lkml.org/lkml/2009/4/21/476,

>On Tue, 2009-04-21 at 15:00 -0500, Scott Wood wrote:
>Subrata Modak wrote:
> > This is a very old one. Doesn´t seem to go away. Reported this earlier
> > on 14th April:
> > http://lkml.org/lkml/2009/4/14/483,
> > 
> > CC [M]  drivers/mtd/maps/sbc8240.o
> > drivers/mtd/maps/sbc8240.c:31:1: warning: "DEBUG" redefined
> > In file included from drivers/mtd/maps/sbc8240.c:23:
> > include/linux/mtd/mtd.h:339:1: warning: this is the location of the
> > previous definition
> > drivers/mtd/maps/sbc8240.c: In function ‘init_sbc8240_mtd’:
> > drivers/mtd/maps/sbc8240.c:172: error: ‘sbc8240_mtd’ undeclared (first
> > use in this function)
> > drivers/mtd/maps/sbc8240.c:172: error: (Each undeclared identifier is
> > reported only once
> > drivers/mtd/maps/sbc8240.c:172: error: for each function it appears in.)
> > drivers/mtd/maps/sbc8240.c: In function ‘cleanup_sbc8240_mtd’:
> > drivers/mtd/maps/sbc8240.c:233: error: ‘sbc8240_mtd’ undeclared (first
> > use in this function)
> 
> This looks like an arch/ppc orphan.  It's not enabled by any defconfig, 
> and it doesn't look like it does anything that physmap_of can't do.
> 
> I'd just remove it.
> 
> -Scott

I tried to gather some more info about this driver from the link
mentioned in Kconfig:
http://www.windriver.com/products/sbc8240/,
without much success.

If there are no issues, can you please apply this patch to remove it ?

To: David Woodhouse <dwmw2@infradead.org>,
To: Scott Wood <scottwood@freescale.com>,
Cc: Jim Cromie <jim.cromie@gmail.com>,
Cc: carolyn.j.smith@exgate.tek.com,
Cc: Adrian Bunk <bunk@kernel.org>,
Cc: Sachin P Sant <sachinp@linux.vnet.ibm.com>,
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>,
Cc: Stephen Rothwell <sfr@canb.auug.org.au>,
Cc: linux-kernel <linux-kernel@vger.kernel.org>,
Cc: Linuxppc-dev <Linuxppc-dev@ozlabs.org>,
Cc: linux-next <linux-next@vger.kernel.org>,
Cc: Alexander Beregalov <a.beregalov@gmail.com>


Signed-off-by: Subrata Modak <subrata@linux.vnet.ibm.com>
Tested-on-PPC64-by: Subrata Modak <subrata@linux.vnet.ibm.com>
---

diff -uprN a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig	2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/Kconfig	2009-06-26 07:39:34.000000000 -0500
@@ -284,13 +284,6 @@ config MTD_L440GX
 
 	  BE VERY CAREFUL.
 
-config MTD_SBC8240
-	tristate "Flash device on SBC8240"
-	depends on MTD_JEDECPROBE && 8260
-	help
-          Flash access on the SBC8240 board from Wind River.  See
-          <http://www.windriver.com/products/sbc8240/>
-
 config MTD_TQM8XXL
 	tristate "CFI Flash device mapped on TQM8XXL"
 	depends on MTD_CFI && TQM8xxL
diff -uprN a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile	2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/Makefile	2009-06-26 07:40:03.000000000 -0500
@@ -50,7 +50,6 @@ obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
 obj-$(CONFIG_MTD_NETtel)	+= nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
 obj-$(CONFIG_MTD_H720X)		+= h720x-flash.o
-obj-$(CONFIG_MTD_SBC8240)	+= sbc8240.o
 obj-$(CONFIG_MTD_IXP4XX)	+= ixp4xx.o
 obj-$(CONFIG_MTD_IXP2000)	+= ixp2000.o
 obj-$(CONFIG_MTD_WRSBC8260)	+= wr_sbc82xx_flash.o
diff -uprN a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
--- a/drivers/mtd/maps/sbc8240.c	2009-06-26 07:36:23.000000000 -0500
+++ b/drivers/mtd/maps/sbc8240.c	1969-12-31 18:00:00.000000000 -0600
@@ -1,250 +0,0 @@
-/*
- * Handle mapping of the flash memory access routines on the SBC8240 board.
- *
- * Carolyn Smith, Tektronix, Inc.
- *
- * This code is GPLed
- */
-
-/*
- * The SBC8240 has 2 flash banks.
- * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
- * It contains the U-Boot code (7 sectors) and the environment (1 sector).
- * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
- * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
- * Both parts are JEDEC compatible.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
-#include <linux/mtd/partitions.h>
-#endif
-
-#define	DEBUG
-
-#ifdef	DEBUG
-# define debugk(fmt,args...)	printk(fmt ,##args)
-#else
-# define debugk(fmt,args...)
-#endif
-
-
-#define WINDOW_ADDR0	0xFFF00000		/* 512 KiB */
-#define WINDOW_SIZE0	0x00080000
-#define BUSWIDTH0	1
-
-#define WINDOW_ADDR1	0xFF000000		/* 4 MiB */
-#define WINDOW_SIZE1	0x00400000
-#define BUSWIDTH1	8
-
-#define MSG_PREFIX "sbc8240:"	/* prefix for our printk()'s */
-#define MTDID	   "sbc8240-%d"	/* for mtdparts= partitioning */
-
-
-static struct map_info sbc8240_map[2] = {
-	{
-		.name           = "sbc8240 Flash Bank #0",
-		.size           = WINDOW_SIZE0,
-		.bankwidth       = BUSWIDTH0,
-	},
-	{
-		.name           = "sbc8240 Flash Bank #1",
-		.size           = WINDOW_SIZE1,
-		.bankwidth       = BUSWIDTH1,
-	}
-};
-
-#define NUM_FLASH_BANKS	ARRAY_SIZE(sbc8240_map)
-
-/*
- * The following defines the partition layout of SBC8240 boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size
- * which is not necessarily the actual flash size. It must correspond
- * to the value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
- */
-
-#ifdef CONFIG_MTD_PARTITIONS
-
-static struct mtd_partition sbc8240_uboot_partitions [] = {
-	/* Bank 0 */
-	{
-		.name =	"U-boot",			/* U-Boot Firmware	*/
-		.offset =	0,
-		.size =	0x00070000,			/*  7 x 64 KiB sectors 	*/
-		.mask_flags = MTD_WRITEABLE,		/*  force read-only	*/
-	},
-	{
-		.name =	"environment",			/* U-Boot environment	*/
-		.offset =	0x00070000,
-		.size =	0x00010000,			/*  1 x 64 KiB sector	*/
-	},
-};
-
-static struct mtd_partition sbc8240_fs_partitions [] = {
-	{
-		.name =	"jffs",				/* JFFS  filesystem	*/
-		.offset =	0,
-		.size =	0x003C0000,			/*  4 * 15 * 64KiB	*/
-	},
-	{
-		.name =	"tmp32",
-		.offset =	0x003C0000,
-		.size =	0x00020000,			/*  4 * 32KiB		*/
-	},
-	{
-		.name =	"tmp8a",
-		.offset =	0x003E0000,
-		.size =	0x00008000,			/*  4 * 8KiB		*/
-	},
-	{
-		.name =	"tmp8b",
-		.offset =	0x003E8000,
-		.size =	0x00008000,			/*  4 * 8KiB		*/
-	},
-	{
-		.name =	"tmp16",
-		.offset =	0x003F0000,
-		.size =	0x00010000,			/*  4 * 16KiB		*/
-	}
-};
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
-	int nums;
-	unsigned char *type;
-	struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-
-
-#endif	/* CONFIG_MTD_PARTITIONS */
-
-
-static int __init init_sbc8240_mtd (void)
-{
-	static struct _cjs {
-		u_long addr;
-		u_long size;
-	} pt[NUM_FLASH_BANKS] = {
-		{
-			.addr = WINDOW_ADDR0,
-			.size = WINDOW_SIZE0
-		},
-		{
-			.addr = WINDOW_ADDR1,
-			.size = WINDOW_SIZE1
-		},
-	};
-
-	int devicesfound = 0;
-	int i,j;
-
-	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-		printk (KERN_NOTICE MSG_PREFIX
-			"Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-
-		sbc8240_map[i].map_priv_1 =
-			(unsigned long) ioremap (pt[i].addr, pt[i].size);
-		if (!sbc8240_map[i].map_priv_1) {
-			printk (MSG_PREFIX "failed to ioremap\n");
-			for (j = 0; j < i; j++) {
-				iounmap((void *) sbc8240_map[j].map_priv_1);
-				sbc8240_map[j].map_priv_1 = 0;
-			}
-			return -EIO;
-		}
-		simple_map_init(&sbc8240_mtd[i]);
-
-		sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-
-		if (sbc8240_mtd[i]) {
-			sbc8240_mtd[i]->module = THIS_MODULE;
-			devicesfound++;
-		} else {
-			if (sbc8240_map[i].map_priv_1) {
-				iounmap((void *) sbc8240_map[i].map_priv_1);
-				sbc8240_map[i].map_priv_1 = 0;
-			}
-		}
-	}
-
-	if (!devicesfound) {
-		printk(KERN_NOTICE MSG_PREFIX
-		       "No suppported flash chips found!\n");
-		return -ENXIO;
-	}
-
-#ifdef CONFIG_MTD_PARTITIONS
-	sbc8240_part_banks[0].mtd_part   = sbc8240_uboot_partitions;
-	sbc8240_part_banks[0].type       = "static image";
-	sbc8240_part_banks[0].nums       = ARRAY_SIZE(sbc8240_uboot_partitions);
-	sbc8240_part_banks[1].mtd_part   = sbc8240_fs_partitions;
-	sbc8240_part_banks[1].type       = "static file system";
-	sbc8240_part_banks[1].nums       = ARRAY_SIZE(sbc8240_fs_partitions);
-
-	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-
-		if (!sbc8240_mtd[i]) continue;
-		if (sbc8240_part_banks[i].nums == 0) {
-			printk (KERN_NOTICE MSG_PREFIX
-				"No partition info available, registering whole device\n");
-			add_mtd_device(sbc8240_mtd[i]);
-		} else {
-			printk (KERN_NOTICE MSG_PREFIX
-				"Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
-			add_mtd_partitions (sbc8240_mtd[i],
-					    sbc8240_part_banks[i].mtd_part,
-					    sbc8240_part_banks[i].nums);
-		}
-	}
-#else
-	printk(KERN_NOTICE MSG_PREFIX
-	       "Registering %d flash banks at once\n", devicesfound);
-
-	for (i = 0; i < devicesfound; i++) {
-		add_mtd_device(sbc8240_mtd[i]);
-	}
-#endif	/* CONFIG_MTD_PARTITIONS */
-
-	return devicesfound == 0 ? -ENXIO : 0;
-}
-
-static void __exit cleanup_sbc8240_mtd (void)
-{
-	int i;
-
-	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-		if (sbc8240_mtd[i]) {
-			del_mtd_device (sbc8240_mtd[i]);
-			map_destroy (sbc8240_mtd[i]);
-		}
-		if (sbc8240_map[i].map_priv_1) {
-			iounmap ((void *) sbc8240_map[i].map_priv_1);
-			sbc8240_map[i].map_priv_1 = 0;
-		}
-	}
-}
-
-module_init (init_sbc8240_mtd);
-module_exit (cleanup_sbc8240_mtd);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-

---
Regards--
Subrata

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox