LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] [POWERPC] Add IRQSTACKS support on ppc32
From: Kumar Gala @ 2008-04-28  6:21 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

* Added allocation and initialization of the irq stacks.  We limit the
  stacks to be in lowmem for ppc32.
* Implemented ppc32 versions of call_do_softirq() and call_handle_irq()
  to switch the stack pointers
* Reworked how we do stack overflow detection.  We now keep around the
  limit of the stack in the thread_struct and compare against the limit
  to see if we've overflowed.  We can now use this on ppc64 if desired.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---

Removed ifdef from init_IRQ since we have a dummy version of irq_ctx_init
in irq.h

 arch/powerpc/Kconfig.debug        |    1 -
 arch/powerpc/kernel/asm-offsets.c |    1 +
 arch/powerpc/kernel/entry_32.S    |    4 ++--
 arch/powerpc/kernel/irq.c         |   10 ++++++++--
 arch/powerpc/kernel/misc_32.S     |   25 +++++++++++++++++++++++++
 arch/powerpc/kernel/process.c     |    2 ++
 arch/powerpc/kernel/setup_32.c    |   21 +++++++++++++++++++++
 include/asm-powerpc/processor.h   |    6 ++++++
 8 files changed, 65 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index a86d8d8..2cf72d2 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -118,7 +118,6 @@ config XMON_DISASSEMBLY

 config IRQSTACKS
 	bool "Use separate kernel stacks when processing interrupts"
-	depends on PPC64
 	help
 	  If you say Y here the kernel will use separate kernel stacks
 	  for handling hard and soft interrupts.  This can help avoid
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index adf1d09..0ef4d41 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -64,6 +64,7 @@ int main(void)
 #endif /* CONFIG_PPC64 */

 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
+	DEFINE(KSP_LIMIT, offsetof(struct thread_struct, ksp_limit));
 	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 84c8686..f33c1fe 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -137,8 +137,8 @@ transfer_to_handler:
 2:	/* if from kernel, check interrupted DOZE/NAP mode and
          * check for stack overflow
          */
-	lwz	r9,THREAD_INFO-THREAD(r12)
-	cmplw	r1,r9			/* if r1 <= current->thread_info */
+	lwz	r9,KSP_LIMIT(r12)
+	cmplw	r1,r9			/* if r1 <= ksp_limit */
 	ble-	stack_ovf		/* then the kernel stack overflowed */
 5:
 #ifdef CONFIG_6xx
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 425616f..2f73f70 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -307,6 +307,7 @@ void do_IRQ(struct pt_regs *regs)
 		if (curtp != irqtp) {
 			struct irq_desc *desc = irq_desc + irq;
 			void *handler = desc->handle_irq;
+			unsigned long saved_sp_limit = current->thread.ksp_limit;
 			if (handler == NULL)
 				handler = &__do_IRQ;
 			irqtp->task = curtp->task;
@@ -319,7 +320,10 @@ void do_IRQ(struct pt_regs *regs)
 				(irqtp->preempt_count & ~SOFTIRQ_MASK) |
 				(curtp->preempt_count & SOFTIRQ_MASK);

+			current->thread.ksp_limit = (unsigned long)irqtp +
+				_ALIGN_UP(sizeof(struct thread_info), 16);
 			call_handle_irq(irq, desc, irqtp, handler);
+			current->thread.ksp_limit = saved_sp_limit;
 			irqtp->task = NULL;


@@ -352,9 +356,7 @@ void __init init_IRQ(void)
 {
 	if (ppc_md.init_IRQ)
 		ppc_md.init_IRQ();
-#ifdef CONFIG_PPC64
 	irq_ctx_init();
-#endif
 }


@@ -383,11 +385,15 @@ void irq_ctx_init(void)
 static inline void do_softirq_onstack(void)
 {
 	struct thread_info *curtp, *irqtp;
+	unsigned long saved_sp_limit = current->thread.ksp_limit;

 	curtp = current_thread_info();
 	irqtp = softirq_ctx[smp_processor_id()];
 	irqtp->task = curtp->task;
+	current->thread.ksp_limit = (unsigned long)irqtp +
+				    _ALIGN_UP(sizeof(struct thread_info), 16);
 	call_do_softirq(irqtp);
+	current->thread.ksp_limit = saved_sp_limit;
 	irqtp->task = NULL;
 }

diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 92ccc6f..89aaaa6 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -32,6 +32,31 @@

 	.text

+#ifdef CONFIG_IRQSTACKS
+_GLOBAL(call_do_softirq)
+	mflr	r0
+	stw	r0,4(r1)
+	stwu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r3)
+	mr	r1,r3
+	bl	__do_softirq
+	lwz	r1,0(r1)
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
+
+_GLOBAL(call_handle_irq)
+	mflr	r0
+	stw	r0,4(r1)
+	mtctr	r6
+	stwu	r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r5)
+	mr	r1,r5
+	bctrl
+	lwz	r1,0(r1)
+	lwz	r0,4(r1)
+	mtlr	r0
+	blr
+#endif /* CONFIG_IRQSTACKS */
+
 /*
  * This returns the high 64 bits of the product of two 64-bit numbers.
  */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 6caad17..7de41c3 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -589,6 +589,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	kregs = (struct pt_regs *) sp;
 	sp -= STACK_FRAME_OVERHEAD;
 	p->thread.ksp = sp;
+	p->thread.ksp_limit = (unsigned long)task_stack_page(p) +
+				_ALIGN_UP(sizeof(struct thread_info), 16);

 #ifdef CONFIG_PPC64
 	if (cpu_has_feature(CPU_FTR_SLB)) {
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 36f6779..5112a4a 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -16,6 +16,7 @@
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/console.h>
+#include <linux/lmb.h>

 #include <asm/io.h>
 #include <asm/prom.h>
@@ -229,6 +230,24 @@ int __init ppc_init(void)

 arch_initcall(ppc_init);

+#ifdef CONFIG_IRQSTACKS
+static void __init irqstack_early_init(void)
+{
+	unsigned int i;
+
+	/* interrupt stacks must be in lowmem, we get that for free on ppc32
+	 * as the lmb is limited to lowmem by LMB_REAL_LIMIT */
+	for_each_possible_cpu(i) {
+		softirq_ctx[i] = (struct thread_info *)
+			__va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+		hardirq_ctx[i] = (struct thread_info *)
+			__va(lmb_alloc(THREAD_SIZE, THREAD_SIZE));
+	}
+}
+#else
+#define irqstack_early_init()
+#endif
+
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
@@ -286,6 +305,8 @@ void __init setup_arch(char **cmdline_p)
 	init_mm.end_data = (unsigned long) _edata;
 	init_mm.brk = klimit;

+	irqstack_early_init();
+
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index fd98ca9..cf83f2d 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -138,6 +138,8 @@ typedef struct {

 struct thread_struct {
 	unsigned long	ksp;		/* Kernel stack pointer */
+	unsigned long	ksp_limit;	/* if ksp <= ksp_limit stack overflow */
+
 #ifdef CONFIG_PPC64
 	unsigned long	ksp_vsid;
 #endif
@@ -182,11 +184,14 @@ struct thread_struct {
 #define ARCH_MIN_TASKALIGN 16

 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
+#define INIT_SP_LIMIT \
+	(_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)


 #ifdef CONFIG_PPC32
 #define INIT_THREAD { \
 	.ksp = INIT_SP, \
+	.ksp_limit = INIT_SP_LIMIT, \
 	.fs = KERNEL_DS, \
 	.pgdir = swapper_pg_dir, \
 	.fpexc_mode = MSR_FE0 | MSR_FE1, \
@@ -194,6 +199,7 @@ struct thread_struct {
 #else
 #define INIT_THREAD  { \
 	.ksp = INIT_SP, \
+	.ksp_limit = INIT_SP_LIMIT, \
 	.regs = (struct pt_regs *)INIT_SP - 1, /* XXX bogus, I think */ \
 	.fs = KERNEL_DS, \
 	.fpr = {0}, \
-- 
1.5.4.1

^ permalink raw reply related

* Re: [PATHC V3] Watchdog on MPC85xx SMP system
From: Kumar Gala @ 2008-04-28  6:28 UTC (permalink / raw)
  To: Chen Gong
  Cc: linuxppc-dev@ozlabs.org list, Wim Van Sebroeck, lkml Mailing List
In-Reply-To: <1209363637-22739-1-git-send-email-g.chen@freescale.com>


On Apr 28, 2008, at 1:20 AM, Chen Gong wrote:
> On Book-E SMP systems each core has its own private watchdog.
> If only one watchdog is enabled, when the core that doesn't
> enable the watchdog is hung, system can't reset because no
> watchdog is running on it. That's bad. It means we must enable
> watchdogs on both cores.
>
> We can use smp_call_function() to send appropriate messages to all  
> the other
> cores to enable and update the watchdog.
>
> Signed-off-by: Chen Gong <g.chen@freescale.com>

In the future Wim should be copied as maintainer of WATCHDOG drivers  
in the kernel.

- k

>
> ---
> Tested on MPC8572DS platform.
>
> drivers/char/watchdog/booke_wdt.c |   34 ++++++++++++++++++++++++++ 
> +-------
> 1 files changed, 27 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/ 
> watchdog/booke_wdt.c
> index d362f5b..b3a37d0 100644
> --- a/drivers/char/watchdog/booke_wdt.c
> +++ b/drivers/char/watchdog/booke_wdt.c
> @@ -6,7 +6,12 @@
>  * Author: Matthew McClintock
>  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
>  *
> - * Copyright 2005 Freescale Semiconductor Inc.
> + * Copyright 2005, 2008 Freescale Semiconductor Inc.
> + *
> + * Changelog:
> + * 	2008-04-28 Chen Gong <g.chen@freescale.com>
> + * 	Add SMP support for MPC85xx system. Tested on
> + * 	MPC8572DS platform
>  *
>  * 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
> @@ -16,6 +21,7 @@
>
> #include <linux/module.h>
> #include <linux/fs.h>
> +#include <linux/smp.h>
> #include <linux/miscdevice.h>
> #include <linux/notifier.h>
> #include <linux/watchdog.h>
> @@ -47,23 +53,31 @@ u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
> #define WDTP(x)		(TCR_WP(x))
> #endif
>
> +static DEFINE_SPINLOCK(booke_wdt_lock);
> +
> +static void __booke_wdt_ping(void *data)
> +{
> +	mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
> +}
> +
> /*
>  * booke_wdt_ping:
>  */
> static __inline__ void booke_wdt_ping(void)
> {
> -	mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
> +	smp_call_function(__booke_wdt_ping, NULL, 0, 0);
> +	__booke_wdt_ping(NULL);
> }
>
> /*
> - * booke_wdt_enable:
> + * __booke_wdt_enable:
>  */
> -static __inline__ void booke_wdt_enable(void)
> +static __inline__ void __booke_wdt_enable(void *data)
> {
> 	u32 val;
>
> 	/* clear status before enabling watchdog */
> -	booke_wdt_ping();
> +	__booke_wdt_ping(NULL);
> 	val = mfspr(SPRN_TCR);
> 	val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
>
> @@ -137,12 +151,15 @@ static int booke_wdt_ioctl (struct inode  
> *inode, struct file *file,
>  */
> static int booke_wdt_open (struct inode *inode, struct file *file)
> {
> +	spin_lock(&booke_wdt_lock);
> 	if (booke_wdt_enabled == 0) {
> 		booke_wdt_enabled = 1;
> -		booke_wdt_enable();
> +		__booke_wdt_enable(NULL);
> +		smp_call_function(__booke_wdt_enable, NULL, 0, 0);
> 		printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled  
> (wdt_period=%d)\n",
> 				booke_wdt_period);
> 	}
> +	spin_unlock(&booke_wdt_lock);
>
> 	return nonseekable_open(inode, file);
> }
> @@ -183,11 +200,14 @@ static int __init booke_wdt_init(void)
> 		return ret;
> 	}
>
> +	spin_lock(&booke_wdt_lock);
> 	if (booke_wdt_enabled == 1) {
> 		printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled  
> (wdt_period=%d)\n",
> 				booke_wdt_period);
> -		booke_wdt_enable();
> +		__booke_wdt_enable(NULL);
> +		smp_call_function(__booke_wdt_enable, NULL, 0, 0);
> 	}
> +	spin_unlock(&booke_wdt_lock);
>
> 	return ret;
> }
> -- 
> 1.5.4

^ permalink raw reply

* Re: [PATCH] powerpc TLF_RESTORE_SIGMASK
From: Roland McGrath @ 2008-04-28  7:30 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, akpm, linux-kernel
In-Reply-To: <18448.10563.385481.904182@cargo.ozlabs.ibm.com>

> Thanks.  That can't go in until some generic changes have gone in
> first, right?  So are you going to push the lot in one go via Andrew,
> or should I wait until the generic part is upstream and then push the
> powerpc bit?

>From what I can see, the related patches are in -mm now, but the powerpc
patch is not.  Linus already said he approved of the patches, so I hope
they can be merged in real soon.  That will simplify the juggling for arch
patches.  That said, there is really no hurry for this change for powerpc;
it's a small optimization.

> Oh, and could you please also fix the occurrence of
> TIF_RESTORE_SIGMASK in arch/ppc/kernel/entry.S when this stuff goes
> in?

Oh, I didn't realize that file was in use (or existed).
Third time's the charm (or is this the fifth time?).


Thanks,
Roland

---
[PATCH] powerpc TLF_RESTORE_SIGMASK

Replace TIF_RESTORE_SIGMASK with TLF_RESTORE_SIGMASK and define
our own set_restore_sigmask() function.  This saves the costly
SMP-safe set_bit operation, which we do not need for the sigmask
flag since TIF_SIGPENDING always has to be set too.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 arch/powerpc/kernel/entry_32.S    |    4 ++--
 arch/powerpc/kernel/signal.c      |   12 ++++++------
 arch/powerpc/kernel/signal_32.c   |    2 +-
 arch/ppc/kernel/entry.S           |    4 ++--
 include/asm-powerpc/thread_info.h |   17 +++++++++++++----
 5 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 84c8686..7e2ecf0 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -667,7 +667,7 @@ user_exc_return:		/* r10 contains MSR_KERNEL here */
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,(31-THREAD_SHIFT)
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED)
+	andi.	r0,r9,_TIF_USER_WORK_MASK
 	bne	do_work
 
 restore_user:
@@ -924,7 +924,7 @@ recheck:
 	lwz	r9,TI_FLAGS(r9)
 	andi.	r0,r9,_TIF_NEED_RESCHED
 	bne-	do_resched
-	andi.	r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK
+	andi.	r0,r9,_TIF_USER_WORK_MASK
 	beq	restore_user
 do_user_signal:			/* r10 contains MSR_KERNEL here */
 	ori	r10,r10,MSR_EE
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index a65a44f..ad55488 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -120,7 +120,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 	int ret;
 	int is32 = is_32bit_task();
 
-	if (test_thread_flag(TIF_RESTORE_SIGMASK))
+	if (current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK)
 		oldset = &current->saved_sigmask;
 	else if (!oldset)
 		oldset = &current->blocked;
@@ -131,9 +131,10 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 	check_syscall_restart(regs, &ka, signr > 0);
 
 	if (signr <= 0) {
+		struct thread_info *ti = current_thread_info();
 		/* No signal to deliver -- put the saved sigmask back */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
-			clear_thread_flag(TIF_RESTORE_SIGMASK);
+		if (ti->local_flags & _TLF_RESTORE_SIGMASK) {
+			ti->local_flags &= ~_TLF_RESTORE_SIGMASK;
 			sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 		}
 		return 0;               /* no signals delivered */
@@ -169,10 +170,9 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
 
 		/*
 		 * A signal was successfully delivered; the saved sigmask is in
-		 * its frame, and we can clear the TIF_RESTORE_SIGMASK flag.
+		 * its frame, and we can clear the TLF_RESTORE_SIGMASK flag.
 		 */
-		if (test_thread_flag(TIF_RESTORE_SIGMASK))
-			clear_thread_flag(TIF_RESTORE_SIGMASK);
+		current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK;
 	}
 
 	return ret;
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index ad69434..4ae16d1 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -243,7 +243,7 @@ long sys_sigsuspend(old_sigset_t mask)
 
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
- 	set_thread_flag(TIF_RESTORE_SIGMASK);
+	set_restore_sigmask();
  	return -ERESTARTNOHAND;
 }
 
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 5f3a5d0..fcd830a 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -647,7 +647,7 @@ user_exc_return:		/* r10 contains MSR_KERNEL here */
 	/* Check current_thread_info()->flags */
 	rlwinm	r9,r1,0,0,18
 	lwz	r9,TI_FLAGS(r9)
-	andi.	r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED)
+	andi.	r0,r9,_TIF_USER_WORK_MASK
 	bne	do_work
 
 restore_user:
@@ -898,7 +898,7 @@ recheck:
 	lwz	r9,TI_FLAGS(r9)
 	andi.	r0,r9,_TIF_NEED_RESCHED
 	bne-	do_resched
-	andi.	r0,r9,_TIF_SIGPENDING
+	andi.	r0,r9,_TIF_USER_WORK_MASK
 	beq	restore_user
 do_user_signal:			/* r10 contains MSR_KERNEL here */
 	ori	r10,r10,MSR_EE
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index d030f5c..e079e81 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -116,7 +116,6 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SECCOMP		10	/* secure computing */
 #define TIF_RESTOREALL		11	/* Restore all regs (implies NOERROR) */
 #define TIF_NOERROR		12	/* Force successful syscall return */
-#define TIF_RESTORE_SIGMASK	13	/* Restore signal mask in do_signal */
 #define TIF_FREEZE		14	/* Freezing for suspend */
 #define TIF_RUNLATCH		15	/* Is the runlatch enabled? */
 #define TIF_ABI_PENDING		16	/* 32/64 bit switch needed */
@@ -134,21 +133,31 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
 #define _TIF_RESTOREALL		(1<<TIF_RESTOREALL)
 #define _TIF_NOERROR		(1<<TIF_NOERROR)
-#define _TIF_RESTORE_SIGMASK	(1<<TIF_RESTORE_SIGMASK)
 #define _TIF_FREEZE		(1<<TIF_FREEZE)
 #define _TIF_RUNLATCH		(1<<TIF_RUNLATCH)
 #define _TIF_ABI_PENDING	(1<<TIF_ABI_PENDING)
 #define _TIF_SYSCALL_T_OR_A	(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
 
-#define _TIF_USER_WORK_MASK	( _TIF_SIGPENDING | \
-				 _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK)
+#define _TIF_USER_WORK_MASK	(_TIF_SIGPENDING | _TIF_NEED_RESCHED)
 #define _TIF_PERSYSCALL_MASK	(_TIF_RESTOREALL|_TIF_NOERROR)
 
 /* Bits in local_flags */
 /* Don't move TLF_NAPPING without adjusting the code in entry_32.S */
 #define TLF_NAPPING		0	/* idle thread enabled NAP mode */
+#define TLF_RESTORE_SIGMASK	1	/* Restore signal mask in do_signal */
 
 #define _TLF_NAPPING		(1 << TLF_NAPPING)
+#define _TLF_RESTORE_SIGMASK	(1 << TLF_RESTORE_SIGMASK)
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK	1
+static inline void set_restore_sigmask(void)
+{
+	struct thread_info *ti = current_thread_info();
+	ti->local_flags |= _TLF_RESTORE_SIGMASK;
+	set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif	/* !__ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 

^ permalink raw reply related

* Linux support MPC7448 L2 ECC errors
From: Assaf Hoffman @ 2008-04-28  7:40 UTC (permalink / raw)
  To: linuxppc-embedded

Hi all,
Can you please tell if MPC7448 L2 ECC error handling is implemented in
any of Linux kernels?
Many thanks.

^ permalink raw reply

* Re: cpu_clock confusion
From: Gabriel Paubert @ 2008-04-28  8:46 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-kernel, benh, linuxppc-dev, tglx, arndb, mingo,
	David Miller
In-Reply-To: <1209029257.3357.55.camel@johannes.berg>

On Thu, Apr 24, 2008 at 11:27:37AM +0200, Johannes Berg wrote:
> On Thu, 2008-04-24 at 02:24 -0700, David Miller wrote:
> > From: Johannes Berg <johannes@sipsolutions.net>
> > Date: Thu, 24 Apr 2008 11:21:52 +0200
> > 
> > > Hmm. Why is that whole cpu_clock stuff in place anyway? powerpc has
> > > perfectly synchronised time across processors with dirt cheap access to
> > > it as well, so why build all this code that only messes it up on top of
> > > it?
> > 
> > Same on sparc64.  These changes add more bugs than they fix.
> 
> I tend to think all this clock business should be done local to those
> arches that aren't capable of providing cheap, useful synchronised and
> accurate clocks themselves. Or be a lib that they can link in if needed.
> As it stands, it seems to me that it all just penalises those
> architectures that have decent clocks.

100% agreed. 

	Gabriel

^ permalink raw reply

* [PATCH 0/2] i2c: Add support for device alias names
From: Jean Delvare @ 2008-04-28  9:30 UTC (permalink / raw)
  To: Linux I2C
  Cc: Laurent, Sievers, linuxppc-dev list, Paul Mundt, Scott Wood, Kay

Hi all,

This is an updated, minimal patchset to add support for device alias
names to the i2c subsystem. It is based on earlier work by Jon Smirl,
Jochen Friedrich and myself.

For 2.6.26-rc1 I'll only attempt to push the first two patches: the one
adding the support for alias names and the one converting the drivers
to make use of it. I've even excluded most of the video drivers from
this patch, as they are a bit more difficult to deal with and I don't
want to break them for rc1. This will come later, together with the
patch removing the old device/driver matching scheme.

I've fixed a number of bugs since the previous iteration, and added a
few missing chunks as well. I hope I caught all the pieces this time
but that's hard to tell given that much of the changes are in arch code
I can't even build. So I would like everyone interested in these two
patches getting in 2.6.26-rc1 to give them good testing on as many
systems as possible, and report to me, ideally by the end of the day.
Sorry for the short notice, but I did my best with the little spare
time I had.

Note that there are RTC patches pending for upstream merge, which will
conflict with my patches. Andrew Morton should push them to Linus
today, so that I can rebase my patches before I send them to Linus
(tomorrow). The current versions of the patches apply on top of
2.6.26-git11.

Thanks,
-- 
Jean Delvare

^ permalink raw reply

* MPC852T Linux Support
From: Ankur Maheshwari @ 2008-04-28  9:22 UTC (permalink / raw)
  To: Linux PPC

Hi all,

I am planning to use MPC-852T on my next card. I want to know whether 
any Linux support is available for MPC-852T.
I have worked with MPC860-Kernel-2.4.4 (MPC8xx) earlier. Can I use the 
same kernel for MPC-852T or do I need to change something.

If MPC852T Evaluation card / linux support is already available, kindly 
send me the pointers.

thanks,
Ankur Maheshwari

^ permalink raw reply

* [PATCH 1/2] i2c: Add support for device alias names
From: Jean Delvare @ 2008-04-28  9:39 UTC (permalink / raw)
  To: Linux I2C
  Cc: Laurent, Sievers, linuxppc-dev list, Paul Mundt, Scott Wood, Kay
In-Reply-To: <20080428113052.6d024bda@hyperion.delvare>

Based on earlier work by Jon Smirl and Jochen Friedrich.

This patch allows new-style i2c chip drivers to have alias names using
the official kernel aliasing system and MODULE_DEVICE_TABLE(). At this
point, the old i2c driver binding scheme (driver_name/type) is still
supported.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Jochen Friedrich <jochen@scram.de>
Cc: Jon Smirl <jonsmirl@gmail.com>
Cc: Kay Sievers <kay.sievers@vrfy.org>
---
One thing I am still not happy with is that the aliases created have a
trailing "*":

$ /sbin/modinfo lm90
filename:       /lib/modules/2.6.25-git11/kernel/drivers/hwmon/lm90.ko
author:         Jean Delvare <khali@linux-fr.org>
description:    LM90/ADM1032 driver
license:        GPL
vermagic:       2.6.25-git11 mod_unload
depends:        hwmon
alias:          i2c:lm90*
alias:          i2c:adm1032*
alias:          i2c:lm99*
alias:          i2c:lm86*
alias:          i2c:max6657*
alias:          i2c:adt7461*
alias:          i2c:max6680*
$

This would cause trouble if one I2C chip name matches the beginning of
another I2C chip name and both chips are supported by different
drivers. This has yet to be seen, but still, I'd like to see this
problem fixed quickly.

 Documentation/i2c/writing-clients          |    3 +
 drivers/gpio/pca953x.c                     |    3 +
 drivers/gpio/pcf857x.c                     |    3 +
 drivers/hwmon/f75375s.c                    |    8 ++--
 drivers/i2c/chips/ds1682.c                 |    3 +
 drivers/i2c/chips/menelaus.c               |    3 +
 drivers/i2c/chips/tps65010.c               |    3 +
 drivers/i2c/chips/tsl2550.c                |    3 +
 drivers/i2c/i2c-core.c                     |   51 +++++++++++++++++++++++-----
 drivers/media/video/cs5345.c               |    3 +
 drivers/media/video/cs53l32a.c             |    3 +
 drivers/media/video/cx25840/cx25840-core.c |    3 +
 drivers/media/video/m52790.c               |    3 +
 drivers/media/video/msp3400-driver.c       |    2 -
 drivers/media/video/mt9m001.c              |    3 +
 drivers/media/video/mt9v022.c              |    3 +
 drivers/media/video/saa7115.c              |    3 +
 drivers/media/video/saa7127.c              |    3 +
 drivers/media/video/saa717x.c              |    3 +
 drivers/media/video/tcm825x.c              |    3 +
 drivers/media/video/tlv320aic23b.c         |    3 +
 drivers/media/video/tuner-core.c           |    3 +
 drivers/media/video/tvaudio.c              |    2 -
 drivers/media/video/upd64031a.c            |    3 +
 drivers/media/video/upd64083.c             |    3 +
 drivers/media/video/v4l2-common.c          |    5 +-
 drivers/media/video/vp27smpx.c             |    3 +
 drivers/media/video/wm8739.c               |    3 +
 drivers/media/video/wm8775.c               |    3 +
 drivers/rtc/rtc-ds1307.c                   |    3 +
 drivers/rtc/rtc-ds1374.c                   |    3 +
 drivers/rtc/rtc-m41t80.c                   |    3 +
 drivers/rtc/rtc-rs5c372.c                  |    3 +
 drivers/rtc/rtc-s35390a.c                  |    3 +
 include/linux/i2c.h                        |    5 +-
 include/linux/mod_devicetable.h            |   11 ++++++
 include/media/v4l2-common.h                |    4 +-
 include/media/v4l2-i2c-drv-legacy.h        |    2 -
 include/media/v4l2-i2c-drv.h               |    2 -
 scripts/mod/file2alias.c                   |   13 +++++++
 40 files changed, 141 insertions(+), 51 deletions(-)

--- linux-2.6.26-rc0.orig/Documentation/i2c/writing-clients	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/Documentation/i2c/writing-clients	2008-04-27 22:09:29.000000000 +0200
@@ -164,7 +164,8 @@ I2C device drivers using this binding mo
 kind of driver in Linux:  they provide a probe() method to bind to
 those devices, and a remove() method to unbind.
 
-	static int foo_probe(struct i2c_client *client);
+	static int foo_probe(struct i2c_client *client,
+			     const struct i2c_device_id *id);
 	static int foo_remove(struct i2c_client *client);
 
 Remember that the i2c_driver does not create those client handles.  The
--- linux-2.6.26-rc0.orig/drivers/gpio/pca953x.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/gpio/pca953x.c	2008-04-27 22:09:29.000000000 +0200
@@ -191,7 +191,8 @@ static void pca953x_setup_gpio(struct pc
 	gc->label = chip->client->name;
 }
 
-static int __devinit pca953x_probe(struct i2c_client *client)
+static int __devinit pca953x_probe(struct i2c_client *client,
+				   const struct i2c_device_id *did)
 {
 	struct pca953x_platform_data *pdata;
 	struct pca953x_chip *chip;
--- linux-2.6.26-rc0.orig/drivers/gpio/pcf857x.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/gpio/pcf857x.c	2008-04-27 22:09:29.000000000 +0200
@@ -142,7 +142,8 @@ static void pcf857x_set16(struct gpio_ch
 
 /*-------------------------------------------------------------------------*/
 
-static int pcf857x_probe(struct i2c_client *client)
+static int pcf857x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	struct pcf857x_platform_data	*pdata;
 	struct pcf857x			*gpio;
--- linux-2.6.26-rc0.orig/drivers/hwmon/f75375s.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/hwmon/f75375s.c	2008-04-27 22:09:29.000000000 +0200
@@ -117,7 +117,8 @@ struct f75375_data {
 static int f75375_attach_adapter(struct i2c_adapter *adapter);
 static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
 static int f75375_detach_client(struct i2c_client *client);
-static int f75375_probe(struct i2c_client *client);
+static int f75375_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
 static int f75375_remove(struct i2c_client *client);
 
 static struct i2c_driver f75375_legacy_driver = {
@@ -628,7 +629,8 @@ static void f75375_init(struct i2c_clien
 
 }
 
-static int f75375_probe(struct i2c_client *client)
+static int f75375_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
 {
 	struct f75375_data *data = i2c_get_clientdata(client);
 	struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
@@ -748,7 +750,7 @@ static int f75375_detect(struct i2c_adap
 	if ((err = i2c_attach_client(client)))
 		goto exit_free;
 
-	if ((err = f75375_probe(client)) < 0)
+	if ((err = f75375_probe(client, NULL)) < 0)
 		goto exit_detach;
 
 	return 0;
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/ds1682.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/ds1682.c	2008-04-27 22:09:29.000000000 +0200
@@ -200,7 +200,8 @@ static struct bin_attribute ds1682_eepro
 /*
  * Called when a ds1682 device is matched with this driver
  */
-static int ds1682_probe(struct i2c_client *client)
+static int ds1682_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	int rc;
 
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/menelaus.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/menelaus.c	2008-04-27 22:09:29.000000000 +0200
@@ -1149,7 +1149,8 @@ static inline void menelaus_rtc_init(str
 
 static struct i2c_driver menelaus_i2c_driver;
 
-static int menelaus_probe(struct i2c_client *client)
+static int menelaus_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
 	struct menelaus_chip	*menelaus;
 	int			rev = 0, val;
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/tps65010.c	2008-04-27 22:08:10.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/tps65010.c	2008-04-27 22:09:29.000000000 +0200
@@ -532,7 +532,8 @@ static int __exit tps65010_remove(struct
 	return 0;
 }
 
-static int tps65010_probe(struct i2c_client *client)
+static int tps65010_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
 	struct tps65010		*tps;
 	int			status;
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/tsl2550.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/tsl2550.c	2008-04-27 22:09:29.000000000 +0200
@@ -364,7 +364,8 @@ static int tsl2550_init_client(struct i2
  */
 
 static struct i2c_driver tsl2550_driver;
-static int __devinit tsl2550_probe(struct i2c_client *client)
+static int __devinit tsl2550_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct tsl2550_data *data;
--- linux-2.6.26-rc0.orig/drivers/i2c/i2c-core.c	2008-04-27 22:07:17.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/i2c-core.c	2008-04-27 22:09:29.000000000 +0200
@@ -48,6 +48,17 @@ static DEFINE_IDR(i2c_adapter_idr);
 
 /* ------------------------------------------------------------------------- */
 
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+						const struct i2c_client *client)
+{
+	while (id->name[0]) {
+		if (strcmp(client->name, id->name) == 0)
+			return id;
+		id++;
+	}
+	return NULL;
+}
+
 static int i2c_device_match(struct device *dev, struct device_driver *drv)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
@@ -59,6 +70,10 @@ static int i2c_device_match(struct devic
 	if (!is_newstyle_driver(driver))
 		return 0;
 
+	/* match on an id table if there is one */
+	if (driver->id_table)
+		return i2c_match_id(driver->id_table, client) != NULL;
+
 	/* new style drivers use the same kind of driver matching policy
 	 * as platform devices or SPI:  compare device and driver IDs.
 	 */
@@ -73,11 +88,17 @@ static int i2c_device_uevent(struct devi
 	struct i2c_client	*client = to_i2c_client(dev);
 
 	/* by definition, legacy drivers can't hotplug */
-	if (dev->driver || !client->driver_name)
+	if (dev->driver)
 		return 0;
 
-	if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
-		return -ENOMEM;
+	if (client->driver_name[0]) {
+		if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
+			return -ENOMEM;
+	} else {
+		if (add_uevent_var(env, "MODALIAS=%s%s",
+				   I2C_MODULE_PREFIX, client->name))
+			return -ENOMEM;
+	}
 	dev_dbg(dev, "uevent\n");
 	return 0;
 }
@@ -90,13 +111,19 @@ static int i2c_device_probe(struct devic
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(dev->driver);
+	const struct i2c_device_id *id;
 	int status;
 
 	if (!driver->probe)
 		return -ENODEV;
 	client->driver = driver;
 	dev_dbg(dev, "probe\n");
-	status = driver->probe(client);
+
+	if (driver->id_table)
+		id = i2c_match_id(driver->id_table, client);
+	else
+		id = NULL;
+	status = driver->probe(client, id);
 	if (status)
 		client->driver = NULL;
 	return status;
@@ -179,9 +206,9 @@ static ssize_t show_client_name(struct d
 static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	return client->driver_name
+	return client->driver_name[0]
 		? sprintf(buf, "%s\n", client->driver_name)
-		: 0;
+		: sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
 }
 
 static struct device_attribute i2c_dev_attrs[] = {
@@ -300,15 +327,21 @@ void i2c_unregister_device(struct i2c_cl
 EXPORT_SYMBOL_GPL(i2c_unregister_device);
 
 
-static int dummy_nop(struct i2c_client *client)
+static int dummy_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	return 0;
+}
+
+static int dummy_remove(struct i2c_client *client)
 {
 	return 0;
 }
 
 static struct i2c_driver dummy_driver = {
 	.driver.name	= "dummy",
-	.probe		= dummy_nop,
-	.remove		= dummy_nop,
+	.probe		= dummy_probe,
+	.remove		= dummy_remove,
 };
 
 /**
--- linux-2.6.26-rc0.orig/drivers/media/video/cs5345.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/cs5345.c	2008-04-27 22:09:29.000000000 +0200
@@ -142,7 +142,8 @@ static int cs5345_command(struct i2c_cli
 
 /* ----------------------------------------------------------------------- */
 
-static int cs5345_probe(struct i2c_client *client)
+static int cs5345_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	/* Check if the adapter supports the needed features */
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
--- linux-2.6.26-rc0.orig/drivers/media/video/cs53l32a.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/cs53l32a.c	2008-04-27 22:09:29.000000000 +0200
@@ -135,7 +135,8 @@ static int cs53l32a_command(struct i2c_c
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int cs53l32a_probe(struct i2c_client *client)
+static int cs53l32a_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
 	int i;
 
--- linux-2.6.26-rc0.orig/drivers/media/video/cx25840/cx25840-core.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/cx25840/cx25840-core.c	2008-04-27 22:09:29.000000000 +0200
@@ -1209,7 +1209,8 @@ static int cx25840_command(struct i2c_cl
 
 /* ----------------------------------------------------------------------- */
 
-static int cx25840_probe(struct i2c_client *client)
+static int cx25840_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
 {
 	struct cx25840_state *state;
 	u32 id;
--- linux-2.6.26-rc0.orig/drivers/media/video/m52790.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/m52790.c	2008-04-27 22:09:29.000000000 +0200
@@ -126,7 +126,8 @@ static int m52790_command(struct i2c_cli
 
 /* i2c implementation */
 
-static int m52790_probe(struct i2c_client *client)
+static int m52790_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	struct m52790_state *state;
 
--- linux-2.6.26-rc0.orig/drivers/media/video/msp3400-driver.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/msp3400-driver.c	2008-04-27 22:09:29.000000000 +0200
@@ -805,7 +805,7 @@ static int msp_resume(struct i2c_client 
 
 /* ----------------------------------------------------------------------- */
 
-static int msp_probe(struct i2c_client *client)
+static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct msp_state *state;
 	int (*thread_func)(void *data) = NULL;
--- linux-2.6.26-rc0.orig/drivers/media/video/mt9m001.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/mt9m001.c	2008-04-27 22:09:29.000000000 +0200
@@ -620,7 +620,8 @@ static void mt9m001_video_remove(struct 
 	soc_camera_video_stop(&mt9m001->icd);
 }
 
-static int mt9m001_probe(struct i2c_client *client)
+static int mt9m001_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
 {
 	struct mt9m001 *mt9m001;
 	struct soc_camera_device *icd;
--- linux-2.6.26-rc0.orig/drivers/media/video/mt9v022.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/mt9v022.c	2008-04-27 22:09:29.000000000 +0200
@@ -745,7 +745,8 @@ static void mt9v022_video_remove(struct 
 	soc_camera_video_stop(&mt9v022->icd);
 }
 
-static int mt9v022_probe(struct i2c_client *client)
+static int mt9v022_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
 {
 	struct mt9v022 *mt9v022;
 	struct soc_camera_device *icd;
--- linux-2.6.26-rc0.orig/drivers/media/video/saa7115.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/saa7115.c	2008-04-27 22:09:29.000000000 +0200
@@ -1450,7 +1450,8 @@ static int saa7115_command(struct i2c_cl
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7115_probe(struct i2c_client *client)
+static int saa7115_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	struct saa711x_state *state;
 	int	i;
--- linux-2.6.26-rc0.orig/drivers/media/video/saa7127.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/saa7127.c	2008-04-27 22:09:29.000000000 +0200
@@ -661,7 +661,8 @@ static int saa7127_command(struct i2c_cl
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_probe(struct i2c_client *client)
+static int saa7127_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	struct saa7127_state *state;
 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
--- linux-2.6.26-rc0.orig/drivers/media/video/saa717x.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/saa717x.c	2008-04-27 22:09:29.000000000 +0200
@@ -1418,7 +1418,8 @@ static int saa717x_command(struct i2c_cl
 /* i2c implementation */
 
 /* ----------------------------------------------------------------------- */
-static int saa717x_probe(struct i2c_client *client)
+static int saa717x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
 {
 	struct saa717x_state *decoder;
 	u8 id = 0;
--- linux-2.6.26-rc0.orig/drivers/media/video/tcm825x.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/tcm825x.c	2008-04-27 22:09:29.000000000 +0200
@@ -840,7 +840,8 @@ static struct v4l2_int_device tcm825x_in
 	},
 };
 
-static int tcm825x_probe(struct i2c_client *client)
+static int tcm825x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *did)
 {
 	struct tcm825x_sensor *sensor = &tcm825x;
 	int rval;
--- linux-2.6.26-rc0.orig/drivers/media/video/tlv320aic23b.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/tlv320aic23b.c	2008-04-27 22:09:29.000000000 +0200
@@ -125,7 +125,8 @@ static int tlv320aic23b_command(struct i
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int tlv320aic23b_probe(struct i2c_client *client)
+static int tlv320aic23b_probe(struct i2c_client *client,
+			      const struct i2c_device_id *id)
 {
 	struct tlv320aic23b_state *state;
 
--- linux-2.6.26-rc0.orig/drivers/media/video/tuner-core.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/tuner-core.c	2008-04-27 22:09:29.000000000 +0200
@@ -1073,7 +1073,8 @@ static void tuner_lookup(struct i2c_adap
 /* During client attach, set_type is called by adapter's attach_inform callback.
    set_type must then be completed by tuner_probe.
  */
-static int tuner_probe(struct i2c_client *client)
+static int tuner_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
 {
 	struct tuner *t;
 	struct tuner *radio;
--- linux-2.6.26-rc0.orig/drivers/media/video/tvaudio.c	2008-04-27 22:07:20.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/tvaudio.c	2008-04-27 22:09:29.000000000 +0200
@@ -1461,7 +1461,7 @@ static struct CHIPDESC chiplist[] = {
 /* ---------------------------------------------------------------------- */
 /* i2c registration                                                       */
 
-static int chip_probe(struct i2c_client *client)
+static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct CHIPSTATE *chip;
 	struct CHIPDESC  *desc;
--- linux-2.6.26-rc0.orig/drivers/media/video/upd64031a.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/upd64031a.c	2008-04-27 22:09:29.000000000 +0200
@@ -195,7 +195,8 @@ static int upd64031a_command(struct i2c_
 
 /* i2c implementation */
 
-static int upd64031a_probe(struct i2c_client *client)
+static int upd64031a_probe(struct i2c_client *client,
+			   const struct i2c_device_id *id)
 {
 	struct upd64031a_state *state;
 	int i;
--- linux-2.6.26-rc0.orig/drivers/media/video/upd64083.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/upd64083.c	2008-04-27 22:09:29.000000000 +0200
@@ -172,7 +172,8 @@ static int upd64083_command(struct i2c_c
 
 /* i2c implementation */
 
-static int upd64083_probe(struct i2c_client *client)
+static int upd64083_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
 	struct upd64083_state *state;
 	int i;
--- linux-2.6.26-rc0.orig/drivers/media/video/v4l2-common.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/v4l2-common.c	2008-04-27 22:09:29.000000000 +0200
@@ -710,7 +710,8 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client
 /* Helper function for I2C legacy drivers */
 
 int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
-		const char *name, int (*probe)(struct i2c_client *))
+		const char *name,
+		int (*probe)(struct i2c_client *, const struct i2c_device_id *))
 {
 	struct i2c_client *client;
 	int err;
@@ -724,7 +725,7 @@ int v4l2_i2c_attach(struct i2c_adapter *
 	client->driver = driver;
 	strlcpy(client->name, name, sizeof(client->name));
 
-	err = probe(client);
+	err = probe(client, NULL);
 	if (err == 0) {
 		i2c_attach_client(client);
 	} else {
--- linux-2.6.26-rc0.orig/drivers/media/video/vp27smpx.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/vp27smpx.c	2008-04-27 22:09:29.000000000 +0200
@@ -121,7 +121,8 @@ static int vp27smpx_command(struct i2c_c
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int vp27smpx_probe(struct i2c_client *client)
+static int vp27smpx_probe(struct i2c_client *client,
+			  const struct i2c_device_id *id)
 {
 	struct vp27smpx_state *state;
 
--- linux-2.6.26-rc0.orig/drivers/media/video/wm8739.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/wm8739.c	2008-04-27 22:09:29.000000000 +0200
@@ -261,7 +261,8 @@ static int wm8739_command(struct i2c_cli
 
 /* i2c implementation */
 
-static int wm8739_probe(struct i2c_client *client)
+static int wm8739_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	struct wm8739_state *state;
 
--- linux-2.6.26-rc0.orig/drivers/media/video/wm8775.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/wm8775.c	2008-04-27 22:09:29.000000000 +0200
@@ -159,7 +159,8 @@ static int wm8775_command(struct i2c_cli
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int wm8775_probe(struct i2c_client *client)
+static int wm8775_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	struct wm8775_state *state;
 
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-ds1307.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-ds1307.c	2008-04-27 22:09:29.000000000 +0200
@@ -326,7 +326,8 @@ static struct bin_attribute nvram = {
 
 static struct i2c_driver ds1307_driver;
 
-static int __devinit ds1307_probe(struct i2c_client *client)
+static int __devinit ds1307_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
 {
 	struct ds1307		*ds1307;
 	int			err = -ENODEV;
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-ds1374.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-ds1374.c	2008-04-27 22:09:29.000000000 +0200
@@ -355,7 +355,8 @@ static const struct rtc_class_ops ds1374
 	.ioctl = ds1374_ioctl,
 };
 
-static int ds1374_probe(struct i2c_client *client)
+static int ds1374_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	struct ds1374 *ds1374;
 	int ret;
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-m41t80.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-m41t80.c	2008-04-27 22:09:29.000000000 +0200
@@ -756,7 +756,8 @@ static struct notifier_block wdt_notifie
  *
  *****************************************************************************
  */
-static int m41t80_probe(struct i2c_client *client)
+static int m41t80_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
 {
 	int i, rc = 0;
 	struct rtc_device *rtc = NULL;
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-rs5c372.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-rs5c372.c	2008-04-27 22:09:29.000000000 +0200
@@ -494,7 +494,8 @@ static void rs5c_sysfs_unregister(struct
 
 static struct i2c_driver rs5c372_driver;
 
-static int rs5c372_probe(struct i2c_client *client)
+static int rs5c372_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	int err = 0;
 	struct rs5c372 *rs5c372;
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-s35390a.c	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-s35390a.c	2008-04-27 22:09:29.000000000 +0200
@@ -195,7 +195,8 @@ static const struct rtc_class_ops s35390
 
 static struct i2c_driver s35390a_driver;
 
-static int s35390a_probe(struct i2c_client *client)
+static int s35390a_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
 {
 	int err;
 	unsigned int i;
--- linux-2.6.26-rc0.orig/include/linux/i2c.h	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/include/linux/i2c.h	2008-04-27 22:09:29.000000000 +0200
@@ -126,7 +126,7 @@ struct i2c_driver {
 	 * With the driver model, device enumeration is NEVER done by drivers;
 	 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
 	 */
-	int (*probe)(struct i2c_client *);
+	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
 	int (*remove)(struct i2c_client *);
 
 	/* driver model interfaces that don't relate to enumeration  */
@@ -140,11 +140,10 @@ struct i2c_driver {
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
 
 	struct device_driver driver;
+	const struct i2c_device_id *id_table;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
-#define I2C_NAME_SIZE	20
-
 /**
  * struct i2c_client - represent an I2C slave device
  * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
--- linux-2.6.26-rc0.orig/include/linux/mod_devicetable.h	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/include/linux/mod_devicetable.h	2008-04-27 22:09:29.000000000 +0200
@@ -368,4 +368,15 @@ struct virtio_device_id {
 };
 #define VIRTIO_DEV_ANY_ID	0xffffffff
 
+/* i2c */
+
+#define I2C_NAME_SIZE	20
+#define I2C_MODULE_PREFIX "i2c:"
+
+struct i2c_device_id {
+	char name[I2C_NAME_SIZE];
+	kernel_ulong_t driver_data;	/* Data private to the driver */
+};
+
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
--- linux-2.6.26-rc0.orig/include/media/v4l2-common.h	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/include/media/v4l2-common.h	2008-04-27 22:09:29.000000000 +0200
@@ -107,9 +107,11 @@ int v4l2_chip_match_host(u32 id_type, u3
 struct i2c_driver;
 struct i2c_adapter;
 struct i2c_client;
+struct i2c_device_id;
 
 int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
-		const char *name, int (*probe)(struct i2c_client *));
+		const char *name,
+		int (*probe)(struct i2c_client *, const struct i2c_device_id *));
 
 /* ------------------------------------------------------------------------- */
 
--- linux-2.6.26-rc0.orig/include/media/v4l2-i2c-drv-legacy.h	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/include/media/v4l2-i2c-drv-legacy.h	2008-04-27 22:09:29.000000000 +0200
@@ -25,7 +25,7 @@ struct v4l2_i2c_driver_data {
 	const char * const name;
 	int driverid;
 	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
-	int (*probe)(struct i2c_client *client);
+	int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
 	int (*remove)(struct i2c_client *client);
 	int (*suspend)(struct i2c_client *client, pm_message_t state);
 	int (*resume)(struct i2c_client *client);
--- linux-2.6.26-rc0.orig/include/media/v4l2-i2c-drv.h	2008-04-27 22:05:00.000000000 +0200
+++ linux-2.6.26-rc0/include/media/v4l2-i2c-drv.h	2008-04-27 22:09:29.000000000 +0200
@@ -30,7 +30,7 @@ struct v4l2_i2c_driver_data {
 	const char * const name;
 	int driverid;
 	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
-	int (*probe)(struct i2c_client *client);
+	int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
 	int (*remove)(struct i2c_client *client);
 	int (*suspend)(struct i2c_client *client, pm_message_t state);
 	int (*resume)(struct i2c_client *client);
--- linux-2.6.26-rc0.orig/scripts/mod/file2alias.c	2008-04-27 22:07:28.000000000 +0200
+++ linux-2.6.26-rc0/scripts/mod/file2alias.c	2008-04-27 22:09:29.000000000 +0200
@@ -576,6 +576,15 @@ static int do_virtio_entry(const char *f
 	return 1;
 }
 
+/* Looks like: i2c:S */
+static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
+			char *alias)
+{
+	sprintf(alias, I2C_MODULE_PREFIX "%s", id->name);
+
+	return 1;
+}
+
 /* Ignore any prefix, eg. v850 prepends _ */
 static inline int sym_is(const char *symbol, const char *name)
 {
@@ -704,6 +713,10 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct virtio_device_id), "virtio",
 			 do_virtio_entry, mod);
+	else if (sym_is(symname, "__mod_i2c_device_table"))
+		do_table(symval, sym->st_size,
+			 sizeof(struct i2c_device_id), "i2c",
+			 do_i2c_entry, mod);
 	free(zeros);
 }
 


-- 
Jean Delvare

^ permalink raw reply

* [PATCH 2/2] i2c: Convert most new-style drivers to use module aliasing
From: Jean Delvare @ 2008-04-28  9:53 UTC (permalink / raw)
  To: Linux I2C
  Cc: Laurent, Sievers, linuxppc-dev list, Paul Mundt, Scott Wood, Kay
In-Reply-To: <20080428113052.6d024bda@hyperion.delvare>

Based on earlier work by Jon Smirl and Jochen Friedrich.

Update most new-style i2c drivers to use standard module aliasing
instead of the old driver_name/type driver matching scheme. I've
left the video drivers apart (except for SoC camera drivers) as
they're a bit more diffcult to deal with, they'll have their own
patch later.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Jon Smirl <jonsmirl@gmail.com>
Cc: Jochen Friedrich <jochen@scram.de>
Cc: Kay Sievers <kay.sievers@vrfy.org>
---
 arch/arm/mach-at91/board-csb337.c         |    3 -
 arch/arm/mach-at91/board-dk.c             |    3 -
 arch/arm/mach-at91/board-eb9200.c         |    3 -
 arch/arm/mach-iop32x/em7210.c             |    3 -
 arch/arm/mach-iop32x/glantank.c           |    4 -
 arch/arm/mach-iop32x/n2100.c              |    4 -
 arch/arm/mach-ixp4xx/dsmg600-setup.c      |    2 
 arch/arm/mach-ixp4xx/nas100d-setup.c      |    2 
 arch/arm/mach-ixp4xx/nslu2-setup.c        |    2 
 arch/arm/mach-omap1/board-h2.c            |    2 
 arch/arm/mach-omap1/board-h3.c            |    3 -
 arch/arm/mach-omap1/board-osk.c           |    1 
 arch/arm/mach-orion5x/db88f5281-setup.c   |    4 -
 arch/arm/mach-orion5x/dns323-setup.c      |    7 --
 arch/arm/mach-orion5x/kurobox_pro-setup.c |    4 -
 arch/arm/mach-orion5x/rd88f5182-setup.c   |    4 -
 arch/arm/mach-orion5x/ts209-setup.c       |    3 -
 arch/arm/mach-pxa/pcm990-baseboard.c      |    5 -
 arch/blackfin/mach-bf533/boards/stamp.c   |    3 -
 arch/blackfin/mach-bf537/boards/stamp.c   |    3 -
 arch/blackfin/mach-bf548/boards/ezkit.c   |    2 
 arch/powerpc/sysdev/fsl_soc.c             |   27 ++++------
 arch/sh/boards/renesas/migor/setup.c      |    3 -
 arch/sh/boards/renesas/r7780rp/setup.c    |    3 -
 drivers/gpio/pca953x.c                    |   23 +-------
 drivers/gpio/pcf857x.c                    |   33 +++++++-----
 drivers/hwmon/f75375s.c                   |   23 ++++----
 drivers/i2c/busses/i2c-taos-evm.c         |    3 -
 drivers/i2c/chips/ds1682.c                |    7 ++
 drivers/i2c/chips/menelaus.c              |    7 ++
 drivers/i2c/chips/tps65010.c              |   29 ++++------
 drivers/i2c/chips/tsl2550.c               |    7 ++
 drivers/media/video/mt9m001.c             |    7 ++
 drivers/media/video/mt9v022.c             |    7 ++
 drivers/rtc/rtc-ds1307.c                  |   63 +++++++++--------------
 drivers/rtc/rtc-ds1374.c                  |    7 ++
 drivers/rtc/rtc-m41t80.c                  |   78 +++++++----------------------
 drivers/rtc/rtc-rs5c372.c                 |   24 ++++----
 drivers/rtc/rtc-s35390a.c                 |    7 ++
 include/linux/i2c.h                       |   12 ++--
 40 files changed, 190 insertions(+), 247 deletions(-)

--- linux-2.6.26-rc0.orig/arch/arm/mach-at91/board-csb337.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-at91/board-csb337.c	2008-04-27 22:09:48.000000000 +0200
@@ -79,8 +79,7 @@ static struct at91_udc_data __initdata c
 
 static struct i2c_board_info __initdata csb337_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-ds1307", 0x68),
-		.type	= "ds1307",
+		I2C_BOARD_INFO("ds1307", 0x68),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-at91/board-dk.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-at91/board-dk.c	2008-04-27 22:09:48.000000000 +0200
@@ -132,8 +132,7 @@ static struct i2c_board_info __initdata 
 		I2C_BOARD_INFO("x9429", 0x28),
 	},
 	{
-		I2C_BOARD_INFO("at24c", 0x50),
-		.type	= "24c1024",
+		I2C_BOARD_INFO("24c1024", 0x50),
 	}
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-at91/board-eb9200.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-at91/board-eb9200.c	2008-04-27 22:09:48.000000000 +0200
@@ -93,8 +93,7 @@ static struct at91_mmc_data __initdata e
 
 static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("at24c", 0x50),
-		.type	= "24c512",
+		I2C_BOARD_INFO("24c512", 0x50),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-iop32x/em7210.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-iop32x/em7210.c	2008-04-27 22:09:48.000000000 +0200
@@ -50,8 +50,7 @@ static struct sys_timer em7210_timer = {
  */
 static struct i2c_board_info __initdata em7210_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
-		.type = "rs5c372a",
+		I2C_BOARD_INFO("rs5c372a", 0x32),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-iop32x/glantank.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-iop32x/glantank.c	2008-04-27 22:09:48.000000000 +0200
@@ -176,12 +176,10 @@ static struct f75375s_platform_data glan
 
 static struct i2c_board_info __initdata glantank_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
-		.type = "rs5c372a",
+		I2C_BOARD_INFO("rs5c372a", 0x32),
 	},
 	{
 		I2C_BOARD_INFO("f75375", 0x2e),
-		.type = "f75375",
 		.platform_data = &glantank_f75375s,
 	},
 };
--- linux-2.6.26-rc0.orig/arch/arm/mach-iop32x/n2100.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-iop32x/n2100.c	2008-04-27 22:09:48.000000000 +0200
@@ -208,12 +208,10 @@ static struct f75375s_platform_data n210
 
 static struct i2c_board_info __initdata n2100_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
-		.type = "rs5c372b",
+		I2C_BOARD_INFO("rs5c372b", 0x32),
 	},
 	{
 		I2C_BOARD_INFO("f75375", 0x2e),
-		.type = "f75375",
 		.platform_data = &n2100_f75375s,
 	},
 };
--- linux-2.6.26-rc0.orig/arch/arm/mach-ixp4xx/dsmg600-setup.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-ixp4xx/dsmg600-setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -65,7 +65,7 @@ static struct platform_device dsmg600_i2
 
 static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
 	{
-		I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+		I2C_BOARD_INFO("pcf8563", 0x51),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-ixp4xx/nas100d-setup.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-ixp4xx/nas100d-setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -54,7 +54,7 @@ static struct platform_device nas100d_fl
 
 static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
 	{
-		I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+		I2C_BOARD_INFO("pcf8563", 0x51),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-ixp4xx/nslu2-setup.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-ixp4xx/nslu2-setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -57,7 +57,7 @@ static struct i2c_gpio_platform_data nsl
 
 static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
 	{
-		I2C_BOARD_INFO("rtc-x1205", 0x6f),
+		I2C_BOARD_INFO("x1205", 0x6f),
 	},
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-omap1/board-h2.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-omap1/board-h2.c	2008-04-27 22:09:48.000000000 +0200
@@ -351,11 +351,9 @@ static void __init h2_init_smc91x(void)
 static struct i2c_board_info __initdata h2_i2c_board_info[] = {
 	{
 		I2C_BOARD_INFO("tps65010", 0x48),
-		.type           = "tps65010",
 		.irq            = OMAP_GPIO_IRQ(58),
 	}, {
 		I2C_BOARD_INFO("isp1301_omap", 0x2d),
-		.type		= "isp1301_omap",
 		.irq		= OMAP_GPIO_IRQ(2),
 	},
 };
--- linux-2.6.26-rc0.orig/arch/arm/mach-omap1/board-h3.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-omap1/board-h3.c	2008-04-27 22:09:48.000000000 +0200
@@ -473,8 +473,7 @@ static struct omap_board_config_kernel h
 
 static struct i2c_board_info __initdata h3_i2c_board_info[] = {
        {
-               I2C_BOARD_INFO("tps65010", 0x48),
-               .type           = "tps65013",
+		I2C_BOARD_INFO("tps65013", 0x48),
                /* .irq         = OMAP_GPIO_IRQ(??), */
        },
 };
--- linux-2.6.26-rc0.orig/arch/arm/mach-omap1/board-osk.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-omap1/board-osk.c	2008-04-27 22:09:48.000000000 +0200
@@ -254,7 +254,6 @@ static struct tps65010_board tps_board =
 static struct i2c_board_info __initdata osk_i2c_board_info[] = {
 	{
 		I2C_BOARD_INFO("tps65010", 0x48),
-		.type		= "tps65010",
 		.irq		= OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
 		.platform_data	= &tps_board,
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-orion5x/db88f5281-setup.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-orion5x/db88f5281-setup.c	2008-04-27 22:57:29.000000000 +0200
@@ -292,9 +292,7 @@ static struct mv643xx_eth_platform_data 
  * RTC DS1339 on I2C bus
  ****************************************************************************/
 static struct i2c_board_info __initdata db88f5281_i2c_rtc = {
-	.driver_name	= "rtc-ds1307",
-	.type		= "ds1339",
-	.addr		= 0x68,
+	I2C_BOARD_INFO("ds1339", 0x68),
 };
 
 /*****************************************************************************
--- linux-2.6.26-rc0.orig/arch/arm/mach-orion5x/dns323-setup.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-orion5x/dns323-setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -220,19 +220,16 @@ static struct platform_device *dns323_pl
 static struct i2c_board_info __initdata dns323_i2c_devices[] = {
 	{
 		I2C_BOARD_INFO("g760a", 0x3e),
-		.type = "g760a",
 	},
 #if 0
 	/* this entry requires the new-style driver model lm75 driver,
 	 * for the meantime "insmod lm75.ko force_lm75=0,0x48" is needed */
 	{
-		I2C_BOARD_INFO("lm75", 0x48),
-		.type = "g751",
+		I2C_BOARD_INFO("g751", 0x48),
 	},
 #endif
 	{
-		I2C_BOARD_INFO("rtc-m41t80", 0x68),
-		.type = "m41t80",
+		I2C_BOARD_INFO("m41t80", 0x68),
 	}
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-orion5x/kurobox_pro-setup.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-orion5x/kurobox_pro-setup.c	2008-04-27 22:56:59.000000000 +0200
@@ -162,9 +162,7 @@ static struct mv643xx_eth_platform_data 
  * RTC 5C372a on I2C bus
  ****************************************************************************/
 static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = {
-       .driver_name    = "rtc-rs5c372",
-       .type           = "rs5c372a",
-       .addr           = 0x32,
+	I2C_BOARD_INFO("rs5c372a", 0x32),
 };
 
 /*****************************************************************************
--- linux-2.6.26-rc0.orig/arch/arm/mach-orion5x/rd88f5182-setup.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-orion5x/rd88f5182-setup.c	2008-04-27 22:58:02.000000000 +0200
@@ -224,9 +224,7 @@ static struct mv643xx_eth_platform_data 
  * RTC DS1338 on I2C bus
  ****************************************************************************/
 static struct i2c_board_info __initdata rd88f5182_i2c_rtc = {
-	.driver_name	= "rtc-ds1307",
-	.type		= "ds1338",
-	.addr		= 0x68,
+	I2C_BOARD_INFO("ds1338", 0x68),
 };
 
 /*****************************************************************************
--- linux-2.6.26-rc0.orig/arch/arm/mach-orion5x/ts209-setup.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-orion5x/ts209-setup.c	2008-04-27 22:58:52.000000000 +0200
@@ -276,8 +276,7 @@ static void __init ts209_find_mac_addr(v
 #define TS209_RTC_GPIO	3
 
 static struct i2c_board_info __initdata qnap_ts209_i2c_rtc = {
-       .driver_name = "rtc-s35390a",
-       .addr        = 0x30,
+	I2C_BOARD_INFO("s35390a", 0x30),
        .irq         = 0,
 };
 
--- linux-2.6.26-rc0.orig/arch/arm/mach-pxa/pcm990-baseboard.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/arm/mach-pxa/pcm990-baseboard.c	2008-04-27 22:09:48.000000000 +0200
@@ -320,16 +320,13 @@ static struct soc_camera_link iclink[] =
 static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
 	{
 		/* Must initialize before the camera(s) */
-		I2C_BOARD_INFO("pca953x", 0x41),
-		.type = "pca9536",
+		I2C_BOARD_INFO("pca9536", 0x41),
 		.platform_data = &pca9536_data,
 	}, {
 		I2C_BOARD_INFO("mt9v022", 0x48),
-		.type = "mt9v022",
 		.platform_data = &iclink[0], /* With extender */
 	}, {
 		I2C_BOARD_INFO("mt9m001", 0x5d),
-		.type = "mt9m001",
 		.platform_data = &iclink[0], /* With extender */
 	},
 };
--- linux-2.6.26-rc0.orig/arch/blackfin/mach-bf533/boards/stamp.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/blackfin/mach-bf533/boards/stamp.c	2008-04-27 22:09:48.000000000 +0200
@@ -499,20 +499,17 @@ static struct i2c_board_info __initdata 
 #if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
 	{
 		I2C_BOARD_INFO("ad7142_joystick", 0x2C),
-		.type = "ad7142_joystick",
 		.irq = 39,
 	},
 #endif
 #if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
-		.type = "pcf8574_lcd",
 	},
 #endif
 #if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
-		.type = "pcf8574_keypad",
 		.irq = 39,
 	},
 #endif
--- linux-2.6.26-rc0.orig/arch/blackfin/mach-bf537/boards/stamp.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/blackfin/mach-bf537/boards/stamp.c	2008-04-27 22:09:48.000000000 +0200
@@ -751,20 +751,17 @@ static struct i2c_board_info __initdata 
 #if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
 	{
 		I2C_BOARD_INFO("ad7142_joystick", 0x2C),
-		.type = "ad7142_joystick",
 		.irq = 55,
 	},
 #endif
 #if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
-		.type = "pcf8574_lcd",
 	},
 #endif
 #if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
-		.type = "pcf8574_keypad",
 		.irq = 72,
 	},
 #endif
--- linux-2.6.26-rc0.orig/arch/blackfin/mach-bf548/boards/ezkit.c	2008-04-27 22:07:12.000000000 +0200
+++ linux-2.6.26-rc0/arch/blackfin/mach-bf548/boards/ezkit.c	2008-04-27 22:09:48.000000000 +0200
@@ -641,13 +641,11 @@ static struct i2c_board_info __initdata 
 #if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_lcd", 0x22),
-		.type = "pcf8574_lcd",
 	},
 #endif
 #if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
 	{
 		I2C_BOARD_INFO("pcf8574_keypad", 0x27),
-		.type = "pcf8574_keypad",
 		.irq = 212,
 	},
 #endif
--- linux-2.6.26-rc0.orig/arch/powerpc/sysdev/fsl_soc.c	2008-04-27 22:07:13.000000000 +0200
+++ linux-2.6.26-rc0/arch/powerpc/sysdev/fsl_soc.c	2008-04-27 22:09:48.000000000 +0200
@@ -418,22 +418,21 @@ arch_initcall(gfar_of_init);
 #include <linux/i2c.h>
 struct i2c_driver_device {
 	char	*of_device;
-	char	*i2c_driver;
 	char	*i2c_type;
 };
 
 static struct i2c_driver_device i2c_devices[] __initdata = {
-	{"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
-	{"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
-	{"ricoh,rv5c386",  "rtc-rs5c372", "rv5c386",},
-	{"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
-	{"dallas,ds1307",  "rtc-ds1307",  "ds1307",},
-	{"dallas,ds1337",  "rtc-ds1307",  "ds1337",},
-	{"dallas,ds1338",  "rtc-ds1307",  "ds1338",},
-	{"dallas,ds1339",  "rtc-ds1307",  "ds1339",},
-	{"dallas,ds1340",  "rtc-ds1307",  "ds1340",},
-	{"stm,m41t00",     "rtc-ds1307",  "m41t00"},
-	{"dallas,ds1374",  "rtc-ds1374",  "rtc-ds1374",},
+	{"ricoh,rs5c372a", "rs5c372a"},
+	{"ricoh,rs5c372b", "rs5c372b"},
+	{"ricoh,rv5c386",  "rv5c386"},
+	{"ricoh,rv5c387a", "rv5c387a"},
+	{"dallas,ds1307",  "ds1307"},
+	{"dallas,ds1337",  "ds1337"},
+	{"dallas,ds1338",  "ds1338"},
+	{"dallas,ds1339",  "ds1339"},
+	{"dallas,ds1340",  "ds1340"},
+	{"stm,m41t00",     "m41t00"},
+	{"dallas,ds1374",  "rtc-ds1374"},
 };
 
 static int __init of_find_i2c_driver(struct device_node *node,
@@ -444,9 +443,7 @@ static int __init of_find_i2c_driver(str
 	for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
 		if (!of_device_is_compatible(node, i2c_devices[i].of_device))
 			continue;
-		if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
-			    KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
-		    strlcpy(info->type, i2c_devices[i].i2c_type,
+		if (strlcpy(info->type, i2c_devices[i].i2c_type,
 			    I2C_NAME_SIZE) >= I2C_NAME_SIZE)
 			return -ENOMEM;
 		return 0;
--- linux-2.6.26-rc0.orig/arch/sh/boards/renesas/migor/setup.c	2008-04-27 22:07:13.000000000 +0200
+++ linux-2.6.26-rc0/arch/sh/boards/renesas/migor/setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -199,8 +199,7 @@ static struct platform_device *migor_dev
 
 static struct i2c_board_info __initdata migor_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
-		.type   = "rs5c372b",
+		I2C_BOARD_INFO("rs5c372b", 0x32),
 	},
 	{
 		I2C_BOARD_INFO("migor_ts", 0x51),
--- linux-2.6.26-rc0.orig/arch/sh/boards/renesas/r7780rp/setup.c	2008-04-27 22:07:13.000000000 +0200
+++ linux-2.6.26-rc0/arch/sh/boards/renesas/r7780rp/setup.c	2008-04-27 22:09:48.000000000 +0200
@@ -199,8 +199,7 @@ static struct platform_device smbus_devi
 
 static struct i2c_board_info __initdata highlander_i2c_devices[] = {
 	{
-		I2C_BOARD_INFO("rtc-rs5c372", 0x32),
-		.type	= "r2025sd",
+		I2C_BOARD_INFO("r2025sd", 0x32),
 	},
 };
 
--- linux-2.6.26-rc0.orig/drivers/gpio/pca953x.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/gpio/pca953x.c	2008-04-27 22:09:48.000000000 +0200
@@ -23,13 +23,7 @@
 #define PCA953X_INVERT         2
 #define PCA953X_DIRECTION      3
 
-/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
-struct pca953x_desc {
-	char		name[I2C_NAME_SIZE];
-	unsigned long	driver_data;
-};
-
-static const struct pca953x_desc pca953x_descs[] = {
+static const struct i2c_device_id pca953x_id[] = {
 	{ "pca9534", 8, },
 	{ "pca9535", 16, },
 	{ "pca9536", 4, },
@@ -37,7 +31,9 @@ static const struct pca953x_desc pca953x
 	{ "pca9538", 8, },
 	{ "pca9539", 16, },
 	/* REVISIT several pca955x parts should work here too */
+	{ }
 };
+MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
 struct pca953x_chip {
 	unsigned gpio_start;
@@ -192,26 +188,16 @@ static void pca953x_setup_gpio(struct pc
 }
 
 static int __devinit pca953x_probe(struct i2c_client *client,
-				   const struct i2c_device_id *did)
+				   const struct i2c_device_id *id)
 {
 	struct pca953x_platform_data *pdata;
 	struct pca953x_chip *chip;
 	int ret, i;
-	const struct pca953x_desc *id = NULL;
 
 	pdata = client->dev.platform_data;
 	if (pdata == NULL)
 		return -ENODEV;
 
-	/* this loop vanishes when we get i2c_device_id */
-	for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
-		if (!strcmp(pca953x_descs[i].name, client->name)) {
-			id = pca953x_descs + i;
-			break;
-		}
-	if (!id)
-		return -ENODEV;
-
 	chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
 	if (chip == NULL)
 		return -ENOMEM;
@@ -291,6 +277,7 @@ static struct i2c_driver pca953x_driver 
 	},
 	.probe		= pca953x_probe,
 	.remove		= pca953x_remove,
+	.id_table	= pca953x_id,
 };
 
 static int __init pca953x_init(void)
--- linux-2.6.26-rc0.orig/drivers/gpio/pcf857x.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/gpio/pcf857x.c	2008-04-27 22:09:48.000000000 +0200
@@ -26,6 +26,21 @@
 #include <asm/gpio.h>
 
 
+static const struct i2c_device_id pcf857x_id[] = {
+	{ "pcf8574", 8 },
+	{ "pca8574", 8 },
+	{ "pca9670", 8 },
+	{ "pca9672", 8 },
+	{ "pca9674", 8 },
+	{ "pcf8575", 16 },
+	{ "pca8575", 16 },
+	{ "pca9671", 16 },
+	{ "pca9673", 16 },
+	{ "pca9675", 16 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pcf857x_id);
+
 /*
  * The pcf857x, pca857x, and pca967x chips only expose one read and one
  * write register.  Writing a "one" bit (to match the reset state) lets
@@ -172,13 +187,8 @@ static int pcf857x_probe(struct i2c_clie
 	 *
 	 * NOTE: we don't distinguish here between *4 and *4a parts.
 	 */
-	if (strcmp(client->name, "pcf8574") == 0
-			|| strcmp(client->name, "pca8574") == 0
-			|| strcmp(client->name, "pca9670") == 0
-			|| strcmp(client->name, "pca9672") == 0
-			|| strcmp(client->name, "pca9674") == 0
-			) {
-		gpio->chip.ngpio = 8;
+	gpio->chip.ngpio = id->driver_data;
+	if (gpio->chip.ngpio == 8) {
 		gpio->chip.direction_input = pcf857x_input8;
 		gpio->chip.get = pcf857x_get8;
 		gpio->chip.direction_output = pcf857x_output8;
@@ -198,13 +208,7 @@ static int pcf857x_probe(struct i2c_clie
 	 *
 	 * NOTE: we don't distinguish here between '75 and '75c parts.
 	 */
-	} else if (strcmp(client->name, "pcf8575") == 0
-			|| strcmp(client->name, "pca8575") == 0
-			|| strcmp(client->name, "pca9671") == 0
-			|| strcmp(client->name, "pca9673") == 0
-			|| strcmp(client->name, "pca9675") == 0
-			) {
-		gpio->chip.ngpio = 16;
+	} else if (gpio->chip.ngpio == 16) {
 		gpio->chip.direction_input = pcf857x_input16;
 		gpio->chip.get = pcf857x_get16;
 		gpio->chip.direction_output = pcf857x_output16;
@@ -313,6 +317,7 @@ static struct i2c_driver pcf857x_driver 
 	},
 	.probe	= pcf857x_probe,
 	.remove	= pcf857x_remove,
+	.id_table = pcf857x_id,
 };
 
 static int __init pcf857x_init(void)
--- linux-2.6.26-rc0.orig/drivers/hwmon/f75375s.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/hwmon/f75375s.c	2008-04-27 22:09:48.000000000 +0200
@@ -129,12 +129,20 @@ static struct i2c_driver f75375_legacy_d
 	.detach_client = f75375_detach_client,
 };
 
+static const struct i2c_device_id f75375_id[] = {
+	{ "f75373", f75373 },
+	{ "f75375", f75375 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, f75375_id);
+
 static struct i2c_driver f75375_driver = {
 	.driver = {
 		.name = "f75375",
 	},
 	.probe = f75375_probe,
 	.remove = f75375_remove,
+	.id_table = f75375_id,
 };
 
 static inline int f75375_read8(struct i2c_client *client, u8 reg)
@@ -645,15 +653,7 @@ static int f75375_probe(struct i2c_clien
 	i2c_set_clientdata(client, data);
 	data->client = client;
 	mutex_init(&data->update_lock);
-
-	if (strcmp(client->name, "f75375") == 0)
-		data->kind = f75375;
-	else if (strcmp(client->name, "f75373") == 0)
-		data->kind = f75373;
-	else {
-		dev_err(&client->dev, "Unsupported device: %s\n", client->name);
-		return -ENODEV;
-	}
+	data->kind = id->driver_data;
 
 	if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
 		goto exit_free;
@@ -714,6 +714,7 @@ static int f75375_detect(struct i2c_adap
 	u8 version = 0;
 	int err = 0;
 	const char *name = "";
+	struct i2c_device_id id;
 
 	if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
 		err = -ENOMEM;
@@ -750,7 +751,9 @@ static int f75375_detect(struct i2c_adap
 	if ((err = i2c_attach_client(client)))
 		goto exit_free;
 
-	if ((err = f75375_probe(client, NULL)) < 0)
+	strlcpy(id.name, name, I2C_NAME_SIZE);
+	id.driver_data = kind;
+	if ((err = f75375_probe(client, &id)) < 0)
 		goto exit_detach;
 
 	return 0;
--- linux-2.6.26-rc0.orig/drivers/i2c/busses/i2c-taos-evm.c	2008-04-27 22:04:59.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/busses/i2c-taos-evm.c	2008-04-27 22:09:48.000000000 +0200
@@ -51,7 +51,6 @@ struct taos_data {
 /* TAOS TSL2550 EVM */
 static struct i2c_board_info tsl2550_info = {
 	I2C_BOARD_INFO("tsl2550", 0x39),
-	.type	= "tsl2550",
 };
 
 /* Instantiate i2c devices based on the adapter name */
@@ -59,7 +58,7 @@ static struct i2c_client *taos_instantia
 {
 	if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
 		dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
-			tsl2550_info.driver_name, tsl2550_info.addr);
+			tsl2550_info.type, tsl2550_info.addr);
 		return i2c_new_device(adapter, &tsl2550_info);
 	}
 
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/ds1682.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/ds1682.c	2008-04-27 22:09:48.000000000 +0200
@@ -235,12 +235,19 @@ static int ds1682_remove(struct i2c_clie
 	return 0;
 }
 
+static const struct i2c_device_id ds1682_id[] = {
+	{ "ds1682", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ds1682_id);
+
 static struct i2c_driver ds1682_driver = {
 	.driver = {
 		.name = "ds1682",
 	},
 	.probe = ds1682_probe,
 	.remove = ds1682_remove,
+	.id_table = ds1682_id,
 };
 
 static int __init ds1682_init(void)
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/menelaus.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/menelaus.c	2008-04-27 22:09:48.000000000 +0200
@@ -1243,12 +1243,19 @@ static int __exit menelaus_remove(struct
 	return 0;
 }
 
+static const struct i2c_device_id menelaus_id[] = {
+	{ "menelaus", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, menelaus_id);
+
 static struct i2c_driver menelaus_i2c_driver = {
 	.driver = {
 		.name		= DRIVER_NAME,
 	},
 	.probe		= menelaus_probe,
 	.remove		= __exit_p(menelaus_remove),
+	.id_table	= menelaus_id,
 };
 
 static int __init menelaus_init(void)
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/tps65010.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/tps65010.c	2008-04-27 22:09:48.000000000 +0200
@@ -64,7 +64,6 @@ static struct i2c_driver tps65010_driver
  * as part of board setup by a bootloader.
  */
 enum tps_model {
-	TPS_UNKNOWN = 0,
 	TPS65010,
 	TPS65011,
 	TPS65012,
@@ -554,20 +553,7 @@ static int tps65010_probe(struct i2c_cli
 	mutex_init(&tps->lock);
 	INIT_DELAYED_WORK(&tps->work, tps65010_work);
 	tps->client = client;
-
-	if (strcmp(client->name, "tps65010") == 0)
-		tps->model = TPS65010;
-	else if (strcmp(client->name, "tps65011") == 0)
-		tps->model = TPS65011;
-	else if (strcmp(client->name, "tps65012") == 0)
-		tps->model = TPS65012;
-	else if (strcmp(client->name, "tps65013") == 0)
-		tps->model = TPS65013;
-	else {
-		dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
-		status = -ENODEV;
-		goto fail1;
-	}
+	tps->model = id->driver_data;
 
 	/* the IRQ is active low, but many gpio lines can't support that
 	 * so this driver uses falling-edge triggers instead.
@@ -596,9 +582,6 @@ static int tps65010_probe(struct i2c_cli
 	case TPS65012:
 		tps->por = 1;
 		break;
-	case TPS_UNKNOWN:
-		printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME);
-		break;
 	/* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
 	}
 	tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
@@ -685,12 +668,22 @@ fail1:
 	return status;
 }
 
+static const struct i2c_device_id tps65010_id[] = {
+	{ "tps65010", TPS65010 },
+	{ "tps65011", TPS65011 },
+	{ "tps65012", TPS65012 },
+	{ "tps65013", TPS65013 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tps65010_id);
+
 static struct i2c_driver tps65010_driver = {
 	.driver = {
 		.name	= "tps65010",
 	},
 	.probe	= tps65010_probe,
 	.remove	= __exit_p(tps65010_remove),
+	.id_table = tps65010_id,
 };
 
 /*-------------------------------------------------------------------------*/
--- linux-2.6.26-rc0.orig/drivers/i2c/chips/tsl2550.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/i2c/chips/tsl2550.c	2008-04-27 22:09:48.000000000 +0200
@@ -452,6 +452,12 @@ static int tsl2550_resume(struct i2c_cli
 
 #endif /* CONFIG_PM */
 
+static const struct i2c_device_id tsl2550_id[] = {
+	{ "tsl2550", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tsl2550_id);
+
 static struct i2c_driver tsl2550_driver = {
 	.driver = {
 		.name	= TSL2550_DRV_NAME,
@@ -461,6 +467,7 @@ static struct i2c_driver tsl2550_driver 
 	.resume	= tsl2550_resume,
 	.probe	= tsl2550_probe,
 	.remove	= __devexit_p(tsl2550_remove),
+	.id_table = tsl2550_id,
 };
 
 static int __init tsl2550_init(void)
--- linux-2.6.26-rc0.orig/drivers/media/video/mt9m001.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/mt9m001.c	2008-04-27 22:09:48.000000000 +0200
@@ -697,12 +697,19 @@ static int mt9m001_remove(struct i2c_cli
 	return 0;
 }
 
+static const struct i2c_device_id mt9m001_id[] = {
+	{ "mt9m001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
 static struct i2c_driver mt9m001_i2c_driver = {
 	.driver = {
 		.name = "mt9m001",
 	},
 	.probe		= mt9m001_probe,
 	.remove		= mt9m001_remove,
+	.id_table	= mt9m001_id,
 };
 
 static int __init mt9m001_mod_init(void)
--- linux-2.6.26-rc0.orig/drivers/media/video/mt9v022.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/media/video/mt9v022.c	2008-04-27 22:09:48.000000000 +0200
@@ -819,12 +819,19 @@ static int mt9v022_remove(struct i2c_cli
 	return 0;
 }
 
+static const struct i2c_device_id mt9v022_id[] = {
+	{ "mt9v022", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
 static struct i2c_driver mt9v022_i2c_driver = {
 	.driver = {
 		.name = "mt9v022",
 	},
 	.probe		= mt9v022_probe,
 	.remove		= mt9v022_remove,
+	.id_table	= mt9v022_id,
 };
 
 static int __init mt9v022_mod_init(void)
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-ds1307.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-ds1307.c	2008-04-28 09:26:39.000000000 +0200
@@ -99,45 +99,38 @@ struct ds1307 {
 };
 
 struct chip_desc {
-	char			name[9];
 	unsigned		nvram56:1;
 	unsigned		alarm:1;
-	enum ds_type		type;
 };
 
-static const struct chip_desc chips[] = { {
-	.name		= "ds1307",
-	.type		= ds_1307,
+static const struct chip_desc chips[] = {
+[ds_1307] = {
 	.nvram56	= 1,
-}, {
-	.name		= "ds1337",
-	.type		= ds_1337,
+},
+[ds_1337] = {
 	.alarm		= 1,
-}, {
-	.name		= "ds1338",
-	.type		= ds_1338,
+},
+[ds_1338] = {
 	.nvram56	= 1,
-}, {
-	.name		= "ds1339",
-	.type		= ds_1339,
+},
+[ds_1339] = {
 	.alarm		= 1,
-}, {
-	.name		= "ds1340",
-	.type		= ds_1340,
-}, {
-	.name		= "m41t00",
-	.type		= m41t00,
+},
+[ds_1340] = {
+},
+[m41t00] = {
 }, };
 
-static inline const struct chip_desc *find_chip(const char *s)
-{
-	unsigned i;
-
-	for (i = 0; i < ARRAY_SIZE(chips); i++)
-		if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0)
-			return &chips[i];
-	return NULL;
-}
+static const struct i2c_device_id ds1307_id[] = {
+	{ "ds1307", ds_1307 },
+	{ "ds1337", ds_1337 },
+	{ "ds1338", ds_1338 },
+	{ "ds1339", ds_1339 },
+	{ "ds1340", ds_1340 },
+	{ "m41t00", m41t00 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ds1307_id);
 
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
@@ -332,16 +325,9 @@ static int __devinit ds1307_probe(struct
 	struct ds1307		*ds1307;
 	int			err = -ENODEV;
 	int			tmp;
-	const struct chip_desc	*chip;
+	const struct chip_desc	*chip = &chips[id->driver_data];
 	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);
 
-	chip = find_chip(client->name);
-	if (!chip) {
-		dev_err(&client->dev, "unknown chip type '%s'\n",
-				client->name);
-		return -ENODEV;
-	}
-
 	if (!i2c_check_functionality(adapter,
 			I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
 		return -EIO;
@@ -362,7 +348,7 @@ static int __devinit ds1307_probe(struct
 	ds1307->msg[1].len = sizeof(ds1307->regs);
 	ds1307->msg[1].buf = ds1307->regs;
 
-	ds1307->type = chip->type;
+	ds1307->type = id->driver_data;
 
 	switch (ds1307->type) {
 	case ds_1337:
@@ -551,6 +537,7 @@ static struct i2c_driver ds1307_driver =
 	},
 	.probe		= ds1307_probe,
 	.remove		= __devexit_p(ds1307_remove),
+	.id_table	= ds1307_id,
 };
 
 static int __init ds1307_init(void)
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-ds1374.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-ds1374.c	2008-04-27 22:09:48.000000000 +0200
@@ -41,6 +41,12 @@
 #define DS1374_REG_SR_AF	0x01 /* Alarm Flag */
 #define DS1374_REG_TCR		0x09 /* Trickle Charge */
 
+static const struct i2c_device_id ds1374_id[] = {
+	{ "ds1374", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ds1374_id);
+
 struct ds1374 {
 	struct i2c_client *client;
 	struct rtc_device *rtc;
@@ -430,6 +436,7 @@ static struct i2c_driver ds1374_driver =
 	},
 	.probe = ds1374_probe,
 	.remove = __devexit_p(ds1374_remove),
+	.id_table = ds1374_id,
 };
 
 static int __init ds1374_init(void)
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-m41t80.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-m41t80.c	2008-04-27 22:09:48.000000000 +0200
@@ -60,48 +60,21 @@
 
 #define DRV_VERSION "0.05"
 
-struct m41t80_chip_info {
-	const char *name;
-	u8 features;
-};
-
-static const struct m41t80_chip_info m41t80_chip_info_tbl[] = {
-	{
-		.name		= "m41t80",
-		.features	= 0,
-	},
-	{
-		.name		= "m41t81",
-		.features	= M41T80_FEATURE_HT,
-	},
-	{
-		.name		= "m41t81s",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
-	{
-		.name		= "m41t82",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
-	{
-		.name		= "m41t83",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
-	{
-		.name		= "m41st84",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
-	{
-		.name		= "m41st85",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
-	{
-		.name		= "m41st87",
-		.features	= M41T80_FEATURE_HT | M41T80_FEATURE_BL,
-	},
+static const struct i2c_device_id m41t80_id[] = {
+	{ "m41t80", 0 },
+	{ "m41t81", M41T80_FEATURE_HT },
+	{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+	{ }
 };
+MODULE_DEVICE_TABLE(i2c, m41t80_id);
 
 struct m41t80_data {
-	const struct m41t80_chip_info *chip;
+	u8 features;
 	struct rtc_device *rtc;
 };
 
@@ -208,7 +181,7 @@ static int m41t80_rtc_proc(struct device
 	struct m41t80_data *clientdata = i2c_get_clientdata(client);
 	u8 reg;
 
-	if (clientdata->chip->features & M41T80_FEATURE_BL) {
+	if (clientdata->features & M41T80_FEATURE_BL) {
 		reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
 		seq_printf(seq, "battery\t\t: %s\n",
 			   (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
@@ -759,10 +732,9 @@ static struct notifier_block wdt_notifie
 static int m41t80_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
-	int i, rc = 0;
+	int rc = 0;
 	struct rtc_device *rtc = NULL;
 	struct rtc_time tm;
-	const struct m41t80_chip_info *chip;
 	struct m41t80_data *clientdata = NULL;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
@@ -774,19 +746,6 @@ static int m41t80_probe(struct i2c_clien
 	dev_info(&client->dev,
 		 "chip found, driver version " DRV_VERSION "\n");
 
-	chip = NULL;
-	for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
-		if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
-			chip = &m41t80_chip_info_tbl[i];
-			break;
-		}
-	}
-	if (!chip) {
-		dev_err(&client->dev, "%s is not supported\n", client->name);
-		rc = -ENODEV;
-		goto exit;
-	}
-
 	clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
 	if (!clientdata) {
 		rc = -ENOMEM;
@@ -802,7 +761,7 @@ static int m41t80_probe(struct i2c_clien
 	}
 
 	clientdata->rtc = rtc;
-	clientdata->chip = chip;
+	clientdata->features = id->driver_data;
 	i2c_set_clientdata(client, clientdata);
 
 	/* Make sure HT (Halt Update) bit is cleared */
@@ -811,7 +770,7 @@ static int m41t80_probe(struct i2c_clien
 		goto ht_err;
 
 	if (rc & M41T80_ALHOUR_HT) {
-		if (chip->features & M41T80_FEATURE_HT) {
+		if (clientdata->features & M41T80_FEATURE_HT) {
 			m41t80_get_datetime(client, &tm);
 			dev_info(&client->dev, "HT bit was set!\n");
 			dev_info(&client->dev,
@@ -843,7 +802,7 @@ static int m41t80_probe(struct i2c_clien
 		goto exit;
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
-	if (chip->features & M41T80_FEATURE_HT) {
+	if (clientdata->features & M41T80_FEATURE_HT) {
 		rc = misc_register(&wdt_dev);
 		if (rc)
 			goto exit;
@@ -879,7 +838,7 @@ static int m41t80_remove(struct i2c_clie
 	struct rtc_device *rtc = clientdata->rtc;
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
-	if (clientdata->chip->features & M41T80_FEATURE_HT) {
+	if (clientdata->features & M41T80_FEATURE_HT) {
 		misc_deregister(&wdt_dev);
 		unregister_reboot_notifier(&wdt_notifier);
 	}
@@ -897,6 +856,7 @@ static struct i2c_driver m41t80_driver =
 	},
 	.probe = m41t80_probe,
 	.remove = m41t80_remove,
+	.id_table = m41t80_id,
 };
 
 static int __init m41t80_rtc_init(void)
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-rs5c372.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-rs5c372.c	2008-04-27 22:09:48.000000000 +0200
@@ -69,6 +69,15 @@ enum rtc_type {
 	rtc_rv5c387a,
 };
 
+static const struct i2c_device_id rs5c372_id[] = {
+	{ "rs5c372a", rtc_rs5c372a },
+	{ "rs5c372b", rtc_rs5c372b },
+	{ "rv5c386", rtc_rv5c386 },
+	{ "rv5c387a", rtc_rv5c387a },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rs5c372_id);
+
 /* REVISIT:  this assumes that:
  *  - we're in the 21st century, so it's safe to ignore the century
  *    bit for rv5c38[67] (REG_MONTH bit 7);
@@ -517,25 +526,13 @@ static int rs5c372_probe(struct i2c_clie
 	rs5c372->regs=&rs5c372->buf[1];
 
 	rs5c372->client = client;
+	rs5c372->type = id->driver_data;
 	i2c_set_clientdata(client, rs5c372);
 
 	err = rs5c_get_regs(rs5c372);
 	if (err < 0)
 		goto exit_kfree;
 
-	if (strcmp(client->name, "rs5c372a") == 0)
-		rs5c372->type = rtc_rs5c372a;
-	else if (strcmp(client->name, "rs5c372b") == 0)
-		rs5c372->type = rtc_rs5c372b;
-	else if (strcmp(client->name, "rv5c386") == 0)
-		rs5c372->type = rtc_rv5c386;
-	else if (strcmp(client->name, "rv5c387a") == 0)
-		rs5c372->type = rtc_rv5c387a;
-	else {
-		rs5c372->type = rtc_rs5c372b;
-		dev_warn(&client->dev, "assuming rs5c372b\n");
-	}
-
 	/* clock may be set for am/pm or 24 hr time */
 	switch (rs5c372->type) {
 	case rtc_rs5c372a:
@@ -652,6 +649,7 @@ static struct i2c_driver rs5c372_driver 
 	},
 	.probe		= rs5c372_probe,
 	.remove		= rs5c372_remove,
+	.id_table	= rs5c372_id,
 };
 
 static __init int rs5c372_init(void)
--- linux-2.6.26-rc0.orig/drivers/rtc/rtc-s35390a.c	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/drivers/rtc/rtc-s35390a.c	2008-04-28 08:44:20.000000000 +0200
@@ -34,6 +34,12 @@
 #define S35390A_FLAG_RESET	0x80
 #define S35390A_FLAG_TEST	0x01
 
+static const struct i2c_device_id s35390a_id[] = {
+	{ "s35390a", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, s35390a_id);
+
 struct s35390a {
 	struct i2c_client *client[8];
 	struct rtc_device *rtc;
@@ -297,6 +303,7 @@ static struct i2c_driver s35390a_driver 
 	},
 	.probe		= s35390a_probe,
 	.remove		= s35390a_remove,
+	.id_table	= s35390a_id,
 };
 
 static int __init s35390a_rtc_init(void)
--- linux-2.6.26-rc0.orig/include/linux/i2c.h	2008-04-27 22:09:29.000000000 +0200
+++ linux-2.6.26-rc0/include/linux/i2c.h	2008-04-28 08:44:20.000000000 +0200
@@ -229,17 +229,17 @@ struct i2c_board_info {
 };
 
 /**
- * I2C_BOARD_INFO - macro used to list an i2c device and its driver
- * @driver: identifies the driver to use with the device
+ * I2C_BOARD_INFO - macro used to list an i2c device and its address
+ * @dev_type: identifies the device type
  * @dev_addr: the device's address on the bus.
  *
  * This macro initializes essential fields of a struct i2c_board_info,
  * declaring what has been provided on a particular board.  Optional
- * fields (such as the chip type, its associated irq, or device-specific
- * platform_data) are provided using conventional syntax.
+ * fields (such as associated irq, or device-specific platform_data)
+ * are provided using conventional syntax.
  */
-#define I2C_BOARD_INFO(driver,dev_addr) \
-	.driver_name = (driver), .addr = (dev_addr)
+#define I2C_BOARD_INFO(dev_type,dev_addr) \
+	.type = (dev_type), .addr = (dev_addr)
 
 
 /* Add-on boards should register/unregister their devices; e.g. a board


-- 
Jean Delvare

^ permalink raw reply

* Predefined Compiler Flag for CROSS_COMPILE in ELDK
From: rodolfo @ 2008-04-28 11:27 UTC (permalink / raw)
  To: Linuxppc embedded, Rodolfo

Hi,

I using ppc_4xx- cross-compiler for build linux in xup virtex II pro.
How can I change -mpcu compiler flag for a specific vallue for my
board/processor? 

Thanks,

^ permalink raw reply

* Re: [PATCH 1/2] i2c: Add support for device alias names
From: Jon Smirl @ 2008-04-28 14:43 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Kay Sievers, linuxppc-dev list, Paul Mundt, Linux I2C, Scott Wood
In-Reply-To: <20080428113901.2772e9d9@hyperion.delvare>

On 4/28/08, Jean Delvare <khali@linux-fr.org> wrote:
> Based on earlier work by Jon Smirl and Jochen Friedrich.
>
>  This patch allows new-style i2c chip drivers to have alias names using
>  the official kernel aliasing system and MODULE_DEVICE_TABLE(). At this
>  point, the old i2c driver binding scheme (driver_name/type) is still
>  supported.
>
>  Signed-off-by: Jean Delvare <khali@linux-fr.org>
>  Cc: Jochen Friedrich <jochen@scram.de>
>  Cc: Jon Smirl <jonsmirl@gmail.com>
>  Cc: Kay Sievers <kay.sievers@vrfy.org>
>  ---
>  One thing I am still not happy with is that the aliases created have a
>  trailing "*":
>
>  $ /sbin/modinfo lm90
>  filename:       /lib/modules/2.6.25-git11/kernel/drivers/hwmon/lm90.ko
>  author:         Jean Delvare <khali@linux-fr.org>
>  description:    LM90/ADM1032 driver
>  license:        GPL
>  vermagic:       2.6.25-git11 mod_unload
>  depends:        hwmon
>  alias:          i2c:lm90*
>  alias:          i2c:adm1032*
>  alias:          i2c:lm99*
>  alias:          i2c:lm86*
>  alias:          i2c:max6657*
>  alias:          i2c:adt7461*
>  alias:          i2c:max6680*
>  $
>
>  This would cause trouble if one I2C chip name matches the beginning of
>  another I2C chip name and both chips are supported by different
>  drivers. This has yet to be seen, but still, I'd like to see this
>  problem fixed quickly.


Trailing wildcard is always added by file2alias.c:

                if (do_entry(mod->name, symval+i, alias)) {
                        /* Always end in a wildcard, for future extension */
                        if (alias[strlen(alias)-1] != '*')
                                strcat(alias, "*");


Can't the match order be controlled in the makefile? For example if
you had lm905* and lm90*, put lm905* into into the makefile first
which will cause it to appear in the alias file first. But that would
still cause problems if only lm90 was built and you had a lm905
device.

Alternatively you could change the code to append something like a
period to the name string.

sprintf(alias, I2C_MODULE_PREFIX "%s.", id->name);

I was using macros to alter the name strings to move the PowerPC names
into their own namespace.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [PATCH] Add fast little-endian switch system call
From: Christoph Hellwig @ 2008-04-28 14:43 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linux-arch, linuxppc-dev, mtk.manpages
In-Reply-To: <18453.18943.906693.409245@cargo.ozlabs.ibm.com>

Please see Michael Kerrisk on userspace ABI updates.  A nice little
manpage for this gimmick would be helpful, and maybe help other
platforms that want one aswell to implement the same API.

On Mon, Apr 28, 2008 at 01:52:31PM +1000, Paul Mackerras wrote:
> This adds a system call on 64-bit platforms for switching between
> little-endian and big-endian modes that is much faster than doing a
> prctl call.  This system call is handled as a special case right at
> the start of the system call entry code, and because it is a special
> case, it uses a system call number which is out of the range of
> normal system calls, namely 0x1ebe.
> 
> Measurements with lmbench on a 4.2GHz POWER6 showed no measurable
> change in the speed of normal system calls with this patch.
> 
> Switching endianness with this new system call takes around 60ns on a
> 4.2GHz POWER6, compared with around 300ns to switch endian mode with a
> prctl.  This can provide a significant performance advantage for
> emulators for little-endian architectures that want to switch between
> big-endian and little-endian mode frequently, e.g. because they are
> generating instructions sequences on the fly and they want to run
> those sequences in little-endian mode.
> 
> Signed-off-by: Paul Mackerras <paulus@samba.org>
> ---
> 
> diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
> index 215973a..2eb49a7 100644
> --- a/arch/powerpc/kernel/head_64.S
> +++ b/arch/powerpc/kernel/head_64.S
> @@ -239,6 +239,10 @@ instruction_access_slb_pSeries:
>  	.globl	system_call_pSeries
>  system_call_pSeries:
>  	HMT_MEDIUM
> +BEGIN_FTR_SECTION
> +	cmpdi	r0,0x1ebe
> +	beq-	1f
> +END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)

Am I missing something here or does this add a branch for every normal
syscall?

>  	mr	r9,r13
>  	mfmsr	r10
>  	mfspr	r13,SPRN_SPRG3
> @@ -253,6 +257,13 @@ system_call_pSeries:
>  	rfid
>  	b	.	/* prevent speculative execution */
>  
> +/* Fast LE/BE switch system call */
> +1:	mfspr	r12,SPRN_SRR1
> +	xori	r12,r12,MSR_LE
> +	mtspr	SPRN_SRR1,r12
> +	rfid		/* return to userspace */
> +	b	.
> +
>  	STD_EXCEPTION_PSERIES(0xd00, single_step)
>  	STD_EXCEPTION_PSERIES(0xe00, trap_0e)
>  
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
---end quoted text---

^ permalink raw reply

* Re: [PATCH 1/2] i2c: Add support for device alias names
From: Kay Sievers @ 2008-04-28 15:07 UTC (permalink / raw)
  To: Jean Delvare; +Cc: linuxppc-dev list, Paul Mundt, Scott Wood, Linux I2C
In-Reply-To: <20080428113901.2772e9d9@hyperion.delvare>

On Mon, 2008-04-28 at 11:39 +0200, Jean Delvare wrote:
> Based on earlier work by Jon Smirl and Jochen Friedrich.
>=20
> This patch allows new-style i2c chip drivers to have alias names using
> the official kernel aliasing system and MODULE_DEVICE_TABLE(). At this
> point, the old i2c driver binding scheme (driver_name/type) is still
> supported.
>=20
> Signed-off-by: Jean Delvare <khali@linux-fr.org>
> Cc: Jochen Friedrich <jochen@scram.de>
> Cc: Jon Smirl <jonsmirl@gmail.com>
> Cc: Kay Sievers <kay.sievers@vrfy.org>
> ---
> One thing I am still not happy with is that the aliases created have a
> trailing "*":
>=20
> $ /sbin/modinfo lm90
> filename:       /lib/modules/2.6.25-git11/kernel/drivers/hwmon/lm90.ko
> author:         Jean Delvare <khali@linux-fr.org>
> description:    LM90/ADM1032 driver
> license:        GPL
> vermagic:       2.6.25-git11 mod_unload
> depends:        hwmon
> alias:          i2c:lm90*
> alias:          i2c:adm1032*
> alias:          i2c:lm99*
> alias:          i2c:lm86*
> alias:          i2c:max6657*
> alias:          i2c:adt7461*
> alias:          i2c:max6680*
> $
>=20
> This would cause trouble if one I2C chip name matches the beginning of
> another I2C chip name and both chips are supported by different
> drivers. This has yet to be seen, but still, I'd like to see this
> problem fixed quickly.

=EF=BB=BFRight, the trailing "*" is not nice.

We should terminate the string, so the trailing "*" will not match
longer strings. The usual thing is to add a ":" to the end, which would
then show up as
  alias: i2c:max6680:*

See DMI and ACPI:
  alias dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:* apanel
  alias acpi*:ASIM0000:* atlas_btns

If i2c device modaliases could ever contain multiple strings, it should
be:
  alias: i2c*:max6680:*
=EF=BB=BFto match the module, regardless of the order of the strings in the
modalias:

Thanks,
Kay

^ permalink raw reply

* Re: filenames with spaces in /sys?
From: Scott Wood @ 2008-04-28 15:31 UTC (permalink / raw)
  To: Christian Kujau; +Cc: linuxppc-dev, dwmw2
In-Reply-To: <alpine.DEB.1.10.0804272012000.11017@sheep.housecafe.de>

On Sun, Apr 27, 2008 at 08:35:51PM +0200, Christian Kujau wrote:
> I was a bit puzzled today when I came across
> /sys/devices/platform/pmu-battery.0/power_supply/PMU battery 0/power
> and thought to myself: why are there spaces in "PMU battery 0"?

Why not?

> Wouldn't ../pmu-battery.0/power_supply/PMU_battery_0/power be feasible too? 

Feasible, yes, but uglier, and as you point out, changing it now would
risk breaking userspace for little gain.

> I find it rather annoying to special case the spaces whenever to look
> for something in /sys, when I'm so used not to when doing the same
> find/grep/xargs stuff in /usr/src/linux.

If userspace tools make it awkward to deal with filenames with spaces,
let's fix the userspace tools.  /sys is certainly not the only place
they'll be found, and waging war against them is a battle best left for
a couple decades ago.

-Scott

^ permalink raw reply

* [RFC, PATCH 0/7] Power management patches from Scott Wood plus MPC8241 Linkstation
From: Guennadi Liakhovetski @ 2008-04-28 15:37 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras

Hi all

as replies to this email I'm going to post a respin of the last version 
from December 2007 of Scott's patches plus my patch for Linkstation 
standby.

Scott, I upgraded your patches, please, verify, that they still function. 
I added my Sof's as I'm now forwarding them, I believe, this is correct. I 
tried to preserve original CC lists.

<remark>
Knowing how important power management on ARM systems is I'm a bit 
confused about why this is not the case on _embedded_ powerpc.
</remark>

Thanks
Guennadi
---
Guennadi Liakhovetski

^ permalink raw reply

* [PATCH 1/7] pm: Add TLF_SLEEPING hack to delay interrupt delivery when waking from sleep.
From: Guennadi Liakhovetski @ 2008-04-28 15:37 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

The e300 core (and probably most other 6xx chips) can only come out of
sleep mode with an interrupt.  However, interrupts are logically disabled
by the power management layer.

This hack extends the existing doze/nap hack to also suppress the running
of the interrupt handler when in sleep mode.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 arch/powerpc/kernel/entry_32.S    |    6 ++--
 arch/powerpc/kernel/idle_6xx.S    |   41 ++++++++++++++++++++++++++++++++++++-
 include/asm-powerpc/thread_info.h |    2 +
 3 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 69a91bd..4099a6f 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -138,8 +138,8 @@ transfer_to_handler:
 #ifdef CONFIG_6xx
 	tophys(r9,r9)			/* check local flags */
 	lwz	r12,TI_LOCAL_FLAGS(r9)
-	mtcrf	0x01,r12
-	bt-	31-TLF_NAPPING,4f
+	andi.	r8, r12, _TLF_NAPPING | _TLF_SLEEPING
+	bne-	4f
 #endif /* CONFIG_6xx */
 	.globl transfer_to_handler_cont
 transfer_to_handler_cont:
@@ -154,7 +154,7 @@ transfer_to_handler_cont:
 	RFI				/* jump to handler, enable MMU */
 
 #ifdef CONFIG_6xx
-4:	rlwinm	r12,r12,0,~_TLF_NAPPING
+4:	rlwinm	r12,r12,0,~(_TLF_NAPPING | _TLF_SLEEPING)
 	stw	r12,TI_LOCAL_FLAGS(r9)
 	b	power_save_6xx_restore
 #endif
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index 01bcd52..341f474 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -147,16 +147,30 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 	isync
 	b	1b
 
+#ifdef CONFIG_SUSPEND
+ret_from_sleep:
+	.long	ret_from_except
+	.long	ret_from_except
+#endif
+
 /*
  * Return from NAP/DOZE mode, restore some CPU specific registers,
  * we are called with DR/IR still off and r2 containing physical
  * address of current.  R11 points to the exception frame (physical
- * address).  We have to preserve r10.
+ * address).  r8 contains _TLF_NAPPING or _TLF_SLEEPING.  We have to
+ * preserve r10.
  */
 _GLOBAL(power_save_6xx_restore)
 	lwz	r9,_LINK(r11)		/* interrupted in ppc6xx_idle: */
+#ifdef CONFIG_SUSPEND
+	andi.	r12, r8, _TLF_SLEEPING
+#endif
 	stw	r9,_NIP(r11)		/* make it do a blr */
 
+#ifdef CONFIG_SUSPEND
+	bne-	sleep_6xx_restore
+#endif
+
 #ifdef CONFIG_SMP
 	mfspr	r12,SPRN_SPRG3
 	lwz	r11,TI_CPU(r12)		/* get cpu number * 4 */
@@ -185,6 +199,31 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX)
 	b	transfer_to_handler_cont
 
+#ifdef CONFIG_SUSPEND
+sleep_6xx_restore:
+	/*
+	 * SLEEP mode is invoked through the PM subsystem, which means
+	 * that interrupts should be disabled.  However, the hardware
+	 * requires them to be enabled to wake up.  To prevent the
+	 * interrupt from being visible to Linux, return immediately
+	 * rather than run the interrupt handler.
+	 */
+	lis	r9, ret_from_sleep@h
+	ori	r9, r9, ret_from_sleep@l
+	tophys(r9, r9)
+	mtlr	r9
+
+	/*
+	 * Disable interrupts, so that the interrupt doesn't happen
+	 * again until the PM code sets MSR[EE].
+	 */
+	lwz	r9, _MSR(r11)
+	rlwinm	r9, r9, 0, ~MSR_EE
+	stw	r9, _MSR(r11)
+
+	b	transfer_to_handler_cont
+#endif
+
 	.data
 
 _GLOBAL(nap_save_msscr0)
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index 40d5f98..f7cb48b 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -151,8 +151,10 @@ static inline struct thread_info *current_thread_info(void)
 /* Bits in local_flags */
 /* Don't move TLF_NAPPING without adjusting the code in entry_32.S */
 #define TLF_NAPPING		0	/* idle thread enabled NAP mode */
+#define TLF_SLEEPING		1	/* suspend code enabled SLEEP mode */
 
 #define _TLF_NAPPING		(1 << TLF_NAPPING)
+#define _TLF_SLEEPING		(1 << TLF_SLEEPING)
 
 #endif /* __KERNEL__ */
 
-- 
1.5.3.7

^ permalink raw reply related

* [PATCH 2/7] Add 6xx-style HID0_SLEEP support.
From: Guennadi Liakhovetski @ 2008-04-28 15:38 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 arch/powerpc/sysdev/6xx-suspend.S |   52 +++++++++++++++++++++++++++++++++++++
 arch/powerpc/sysdev/Makefile      |    4 +++
 include/asm-powerpc/mpc6xx.h      |    6 ++++
 3 files changed, 62 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/sysdev/6xx-suspend.S
 create mode 100644 include/asm-powerpc/mpc6xx.h

diff --git a/arch/powerpc/sysdev/6xx-suspend.S b/arch/powerpc/sysdev/6xx-suspend.S
new file mode 100644
index 0000000..21cda08
--- /dev/null
+++ b/arch/powerpc/sysdev/6xx-suspend.S
@@ -0,0 +1,52 @@
+/*
+ * Enter and leave sleep state on chips with 6xx-style HID0
+ * power management bits, which don't leave sleep state via reset.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+
+_GLOBAL(mpc6xx_enter_standby)
+	mflr	r4
+
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~(HID0_DOZE | HID0_NAP)
+	oris	r5, r5, HID0_SLEEP@h
+	mtspr	SPRN_HID0, r5
+	isync
+
+	lis	r5, ret_from_standby@h
+	ori	r5, r5, ret_from_standby@l
+	mtlr	r5
+
+	rlwinm	r5, r1, 0, 0, 31-THREAD_SHIFT
+	lwz	r6, TI_LOCAL_FLAGS(r5)
+	ori	r6, r6, _TLF_SLEEPING
+	stw	r6, TI_LOCAL_FLAGS(r5)
+
+	mfmsr	r5
+	ori	r5, r5, MSR_EE
+	oris	r5, r5, MSR_POW@h
+	sync
+	mtmsr	r5
+	isync
+
+1:	b	1b
+
+ret_from_standby:
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~HID0_SLEEP
+	mtspr	SPRN_HID0, r5
+
+	mtlr	r4
+	blr
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 99a77d7..df2b885 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -37,3 +37,7 @@ obj-$(CONFIG_PPC_DCR)		+= dcr.o
 obj-$(CONFIG_8xx)		+= mpc8xx_pic.o cpm1.o
 obj-$(CONFIG_UCODE_PATCH)	+= micropatch.o
 endif
+
+ifeq ($(CONFIG_SUSPEND),y)
+obj-$(CONFIG_6xx)		+= 6xx-suspend.o
+endif
diff --git a/include/asm-powerpc/mpc6xx.h b/include/asm-powerpc/mpc6xx.h
new file mode 100644
index 0000000..effc229
--- /dev/null
+++ b/include/asm-powerpc/mpc6xx.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_POWERPC_MPC6xx_H
+#define __ASM_POWERPC_MPC6xx_H
+
+void mpc6xx_enter_standby(void);
+
+#endif
-- 
1.5.3.7

^ permalink raw reply related

* [PATCH 3/7] mpc83xx: Power Management support
From: Guennadi Liakhovetski @ 2008-04-28 15:38 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

Basic PM support for 83xx.  Standby is implemented as sleep.
Suspend-to-RAM is implemented as "deep sleep" (with the processor
turned off) on 831x.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
The enabling of i-cache at the end of the suspend code somehow fell off of
the code that was sent out in the previous patch (it still works when
booting high, which is what I tested, but not booting low).

The rest of the patchset stays the same.

 arch/powerpc/platforms/83xx/Kconfig       |    5 +
 arch/powerpc/platforms/83xx/Makefile      |    1 +
 arch/powerpc/platforms/83xx/suspend-asm.S |  539 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/83xx/suspend.c     |  423 ++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.c             |   33 ++
 arch/powerpc/sysdev/fsl_soc.h             |   10 +
 arch/powerpc/sysdev/ipic.c                |   71 ++++
 include/asm-powerpc/reg.h                 |    4 +
 include/linux/fsl_devices.h               |   24 ++
 9 files changed, 1110 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/83xx/suspend-asm.S
 create mode 100644 arch/powerpc/platforms/83xx/suspend.c

diff -u a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -192,7 +192,7 @@ config ARCH_HIBERNATION_POSSIBLE
 
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
-	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200
+	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx
 
 config PPC_DCR_NATIVE
 	bool
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index ec305f1..901dbaf 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -6,6 +6,11 @@ menuconfig MPC83xx
 
 if MPC83xx
 
+config PPC_83xx_SUSPEND
+	bool
+	default y
+	depends on SUSPEND
+
 config MPC831x_RDB
 	bool "Freescale MPC831x RDB"
 	select DEFAULT_UIMAGE
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 5a98f88..944369e 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -3,6 +3,7 @@
 #
 obj-y				:= misc.o usb.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_SUSPEND)		+= suspend.o suspend-asm.o
 obj-$(CONFIG_MPC831x_RDB)	+= mpc831x_rdb.o
 obj-$(CONFIG_MPC832x_RDB)	+= mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)	+= mpc834x_mds.o
diff --git a/arch/powerpc/platforms/83xx/suspend-asm.S b/arch/powerpc/platforms/83xx/suspend-asm.S
new file mode 100644
index 0000000..03e29a2
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/suspend-asm.S
@@ -0,0 +1,539 @@
+/*
+ * Enter and leave sleep state on MPC83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/reg.h>
+#include <asm/asm-offsets.h>
+
+#define SS_MEMSAVE	0x00
+#define SS_HID		0x08 /* 3 HIDs */
+#define SS_IABR		0x14 /* 2 IABRs */
+#define SS_IBCR		0x1c
+#define SS_DABR		0x20 /* 2 DABRs */
+#define SS_DBCR		0x28
+#define SS_SP		0x2c
+#define SS_SR		0x30 /* 16 segment registers */
+#define SS_CURRENT	0x70
+#define SS_MSR		0x74
+#define SS_SDR1		0x78
+#define SS_LR		0x7c
+#define SS_SPRG		0x80 /* 4 SPRGs */
+#define SS_DBAT		0x90 /* 8 DBATs */
+#define SS_IBAT		0xd0 /* 8 IBATs */
+#define SS_TB		0x110
+#define SS_CR		0x118
+#define SS_GPREG	0x11c /* r12-r31 */
+#define STATE_SAVE_SIZE 0x16c
+
+	.section .data
+	.align	5
+
+mpc83xx_sleep_save_area:
+	.space	STATE_SAVE_SIZE
+immrbase:
+	.long	0
+
+	.section .text
+	.align	5
+
+	/* r3 = physical address of IMMR */
+_GLOBAL(mpc83xx_enter_deep_sleep)
+	/* Re-use the state saving/restoring code in
+	 * arch/powerpc/kernel/swsusp_32.S, but have
+	 * it call us instead of swsusp_save.
+	 */
+
+	lis	r4, immrbase@ha
+	stw	r3, immrbase@l(r4)
+
+	/* The first 2 words of memory are used to communicate with the
+	 * bootloader, to tell it how to resume.
+	 *
+	 * The first word is the magic number 0xf5153ae5, and the second
+	 * is the pointer to mpc83xx_deep_resume.
+	 *
+	 * The original content of these two words is saved in the state
+	 * save area.
+	 */
+
+	lis	r3, mpc83xx_sleep_save_area@h
+	ori	r3, r3, mpc83xx_sleep_save_area@l
+
+	lis	r4, KERNELBASE@h
+	lwz	r5, 0(r4)
+	lwz	r6, 4(r4)
+
+	stw	r5, SS_MEMSAVE+0(r3)
+	stw	r6, SS_MEMSAVE+4(r3)
+
+	mfspr	r5, SPRN_HID0
+	mfspr	r6, SPRN_HID1
+	mfspr	r7, SPRN_HID2
+
+	stw	r5, SS_HID+0(r3)
+	stw	r6, SS_HID+4(r3)
+	stw	r7, SS_HID+8(r3)
+
+	mfspr	r4, SPRN_IABR
+	mfspr	r5, SPRN_IABR2
+	mfspr	r6, SPRN_IBCR
+	mfspr	r7, SPRN_DABR
+	mfspr	r8, SPRN_DABR2
+	mfspr	r9, SPRN_DBCR
+
+	stw	r4, SS_IABR+0(r3)
+	stw	r5, SS_IABR+4(r3)
+	stw	r6, SS_IBCR(r3)
+	stw	r7, SS_DABR+0(r3)
+	stw	r8, SS_DABR+4(r3)
+	stw	r9, SS_DBCR(r3)
+
+	mfspr	r4, SPRN_SPRG0
+	mfspr	r5, SPRN_SPRG1
+	mfspr	r6, SPRN_SPRG2
+	mfspr	r7, SPRN_SPRG3
+	mfsdr1	r8
+
+	stw	r4, SS_SPRG+0(r3)
+	stw	r5, SS_SPRG+4(r3)
+	stw	r6, SS_SPRG+8(r3)
+	stw	r7, SS_SPRG+12(r3)
+	stw	r8, SS_SDR1(r3)
+
+	mfspr	r4, SPRN_DBAT0U
+	mfspr	r5, SPRN_DBAT0L
+	mfspr	r6, SPRN_DBAT1U
+	mfspr	r7, SPRN_DBAT1L
+
+	stw	r4, SS_DBAT+0x00(r3)
+	stw	r5, SS_DBAT+0x04(r3)
+	stw	r6, SS_DBAT+0x08(r3)
+	stw	r7, SS_DBAT+0x0c(r3)
+
+	mfspr	r4, SPRN_DBAT2U
+	mfspr	r5, SPRN_DBAT2L
+	mfspr	r6, SPRN_DBAT3U
+	mfspr	r7, SPRN_DBAT3L
+
+	stw	r4, SS_DBAT+0x10(r3)
+	stw	r5, SS_DBAT+0x14(r3)
+	stw	r6, SS_DBAT+0x18(r3)
+	stw	r7, SS_DBAT+0x1c(r3)
+
+	mfspr	r4, SPRN_DBAT4U
+	mfspr	r5, SPRN_DBAT4L
+	mfspr	r6, SPRN_DBAT5U
+	mfspr	r7, SPRN_DBAT5L
+
+	stw	r4, SS_DBAT+0x20(r3)
+	stw	r5, SS_DBAT+0x24(r3)
+	stw	r6, SS_DBAT+0x28(r3)
+	stw	r7, SS_DBAT+0x2c(r3)
+
+	mfspr	r4, SPRN_DBAT6U
+	mfspr	r5, SPRN_DBAT6L
+	mfspr	r6, SPRN_DBAT7U
+	mfspr	r7, SPRN_DBAT7L
+
+	stw	r4, SS_DBAT+0x30(r3)
+	stw	r5, SS_DBAT+0x34(r3)
+	stw	r6, SS_DBAT+0x38(r3)
+	stw	r7, SS_DBAT+0x3c(r3)
+
+	mfspr	r4, SPRN_IBAT0U
+	mfspr	r5, SPRN_IBAT0L
+	mfspr	r6, SPRN_IBAT1U
+	mfspr	r7, SPRN_IBAT1L
+
+	stw	r4, SS_IBAT+0x00(r3)
+	stw	r5, SS_IBAT+0x04(r3)
+	stw	r6, SS_IBAT+0x08(r3)
+	stw	r7, SS_IBAT+0x0c(r3)
+
+	mfspr	r4, SPRN_IBAT2U
+	mfspr	r5, SPRN_IBAT2L
+	mfspr	r6, SPRN_IBAT3U
+	mfspr	r7, SPRN_IBAT3L
+
+	stw	r4, SS_IBAT+0x10(r3)
+	stw	r5, SS_IBAT+0x14(r3)
+	stw	r6, SS_IBAT+0x18(r3)
+	stw	r7, SS_IBAT+0x1c(r3)
+
+	mfspr	r4, SPRN_IBAT4U
+	mfspr	r5, SPRN_IBAT4L
+	mfspr	r6, SPRN_IBAT5U
+	mfspr	r7, SPRN_IBAT5L
+
+	stw	r4, SS_IBAT+0x20(r3)
+	stw	r5, SS_IBAT+0x24(r3)
+	stw	r6, SS_IBAT+0x28(r3)
+	stw	r7, SS_IBAT+0x2c(r3)
+
+	mfspr	r4, SPRN_IBAT6U
+	mfspr	r5, SPRN_IBAT6L
+	mfspr	r6, SPRN_IBAT7U
+	mfspr	r7, SPRN_IBAT7L
+
+	stw	r4, SS_IBAT+0x30(r3)
+	stw	r5, SS_IBAT+0x34(r3)
+	stw	r6, SS_IBAT+0x38(r3)
+	stw	r7, SS_IBAT+0x3c(r3)
+
+	mfmsr	r4
+	mflr	r5
+	mfcr	r6
+
+	stw	r4, SS_MSR(r3)
+	stw	r5, SS_LR(r3)
+	stw	r6, SS_CR(r3)
+	stw	r1, SS_SP(r3)
+	stw	r2, SS_CURRENT(r3)
+
+1:	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	r4, r6
+	bne	1b
+
+	stw	r4, SS_TB+0(r3)
+	stw	r5, SS_TB+4(r3)
+
+	stmw	r12, SS_GPREG(r3)
+
+	li	r4, 0
+	addi	r6, r3, SS_SR-4
+1:	mfsrin	r5, r4
+	stwu	r5, 4(r6)
+	addis	r4, r4, 0x1000
+	cmpwi	r4, 0
+	bne	1b
+
+	/* Disable machine checks and critical exceptions */
+	mfmsr	r4
+	rlwinm	r4, r4, 0, ~MSR_CE
+	rlwinm	r4, r4, 0, ~MSR_ME
+	mtmsr	r4
+	isync
+
+#define TMP_VIRT_IMMR		0xf0000000
+#define DEFAULT_IMMR_VALUE	0xff400000
+#define IMMRBAR_BASE		0x0000
+
+	lis	r4, immrbase@ha
+	lwz	r4, immrbase@l(r4)
+
+	/* Use DBAT0 to address the current IMMR space */
+
+	ori	r4, r4, 0x002a
+	mtspr	SPRN_DBAT0L, r4
+	lis	r8, TMP_VIRT_IMMR@h
+	ori	r4, r8, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT0U, r4
+	isync
+
+	/* Use DBAT1 to address the original IMMR space */
+
+	lis	r4, DEFAULT_IMMR_VALUE@h
+	ori	r4, r4, 0x002a
+	mtspr	SPRN_DBAT1L, r4
+	lis	r9, (TMP_VIRT_IMMR + 0x01000000)@h
+	ori	r4, r9, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT1U, r4
+	isync
+
+	/* Use DBAT2 to address the beginning of RAM.  This isn't done
+	 * using the normal virtual mapping, because with page debugging
+	 * enabled it will be read-only. */
+
+	li	r4, 0x0002
+	mtspr	SPRN_DBAT2L, r4
+	lis	r4, KERNELBASE@h
+	ori	r4, r4, 0x001e	/* 1 MByte accessable from Kernel Space only */
+	mtspr	SPRN_DBAT2U, r4
+	isync
+
+	/* Flush the cache with our BAT, as there will be TLB misses
+	 * otherwise if page debugging is enabled, and these misses
+	 * will disturb the PLRU algorithm.
+	 */
+
+	bl	__flush_disable_L1
+
+	/* Keep the i-cache enabled, so the hack below for low-boot
+	 * flash will work.
+	 */
+	mfspr	r3, SPRN_HID0
+	ori	r3, r3, HID0_ICE
+	mtspr	SPRN_HID0, r3
+	isync
+
+	lis	r6, 0xf515
+	ori	r6, r6, 0x3ae5
+
+	lis	r7, mpc83xx_deep_resume@h
+	ori	r7, r7, mpc83xx_deep_resume@l
+	tophys(r7, r7)
+
+	lis	r5, KERNELBASE@h
+	stw	r6, 0(r5)
+	stw	r7, 4(r5)
+
+	/* Reset BARs */
+
+	li	r4, 0
+	stw	r4, 0x0024(r8)
+	stw	r4, 0x002c(r8)
+	stw	r4, 0x0034(r8)
+	stw	r4, 0x003c(r8)
+	stw	r4, 0x0064(r8)
+	stw	r4, 0x006c(r8)
+
+	/* Rev 1 of the 8313 has problems with wakeup events that are
+	 * pending during the transition to deep sleep state (such as if
+	 * the PCI host sets the state to D3 and then D0 in rapid
+	 * succession).  This check shrinks the race window somewhat.
+	 *
+	 * See erratum PCI23, though the problem is not limited
+	 * to PCI.
+	 */
+
+	lwz	r3, 0x0b04(r8)
+	andi.	r3, r3, 1
+	bne-	mpc83xx_deep_resume
+
+	/* Move IMMR back to the default location, following the
+	 * procedure specified in the MPC8313 manual.
+	 */
+	lwz	r4, IMMRBAR_BASE(r8)
+	isync
+	lis	r4, DEFAULT_IMMR_VALUE@h
+	stw	r4, IMMRBAR_BASE(r8)
+	lis	r4, KERNELBASE@h
+	lwz	r4, 0(r4)
+	isync
+	lwz	r4, IMMRBAR_BASE(r9)
+	mr	r8, r9
+	isync
+
+	/* Check the Reset Configuration Word to see whether flash needs
+	 * to be mapped at a low address or a high address.
+	 */
+
+	lwz	r4, 0x0904(r8)
+	andis.	r4, r4, 0x0400
+	li	r4, 0
+	beq	boot_low
+	lis	r4, 0xff80
+boot_low:
+	stw	r4, 0x0020(r8)
+	lis	r7, 0x8000
+	ori	r7, r7, 0x0016
+
+	mfspr	r5, SPRN_HID0
+	rlwinm	r5, r5, 0, ~(HID0_DOZE | HID0_NAP)
+	oris	r5, r5, HID0_SLEEP@h
+	mtspr	SPRN_HID0, r5
+	isync
+
+	mfmsr	r5
+	oris	r5, r5, MSR_POW@h
+
+	/* Enable the flash mapping at the appropriate address.  This
+	 * mapping will override the RAM mapping, so there's no need to
+	 * disable the latter.  This must be done inside the same cache
+	 * line as setting MSR_POW, so that no instruction fetches from
+	 * RAM happen after the flash mapping is turned on.
+	 */
+
+	.align	5
+	stw	r7, 0x0024(r8)
+	sync
+	isync
+	mtmsr	r5
+	isync
+1:	b	1b
+
+mpc83xx_deep_resume:
+	lis	r4, 1f@h
+	ori	r4, r4, 1f@l
+	tophys(r4, r4)
+	mtsrr0	r4
+
+	mfmsr	r4
+	rlwinm	r4, r4, 0, ~(MSR_IR | MSR_DR)
+	mtsrr1	r4
+
+	rfi
+
+1:	tlbia
+	bl	__inval_enable_L1
+
+	lis	r3, mpc83xx_sleep_save_area@h
+	ori	r3, r3, mpc83xx_sleep_save_area@l
+	tophys(r3, r3)
+
+	lwz	r5, SS_MEMSAVE+0(r3)
+	lwz	r6, SS_MEMSAVE+4(r3)
+
+	stw	r5, 0(0)
+	stw	r6, 4(0)
+
+	lwz	r5, SS_HID+0(r3)
+	lwz	r6, SS_HID+4(r3)
+	lwz	r7, SS_HID+8(r3)
+
+	mtspr	SPRN_HID0, r5
+	mtspr	SPRN_HID1, r6
+	mtspr	SPRN_HID2, r7
+
+	lwz	r4, SS_IABR+0(r3)
+	lwz	r5, SS_IABR+4(r3)
+	lwz	r6, SS_IBCR(r3)
+	lwz	r7, SS_DABR+0(r3)
+	lwz	r8, SS_DABR+4(r3)
+	lwz	r9, SS_DBCR(r3)
+
+	mtspr	SPRN_IABR, r4
+	mtspr	SPRN_IABR2, r5
+	mtspr	SPRN_IBCR, r6
+	mtspr	SPRN_DABR, r7
+	mtspr	SPRN_DABR2, r8
+	mtspr	SPRN_DBCR, r9
+
+	li	r4, 0
+	addi	r6, r3, SS_SR-4
+1:	lwzu	r5, 4(r6)
+	mtsrin	r5, r4
+	addis	r4, r4, 0x1000
+	cmpwi	r4, 0
+	bne	1b
+
+	lwz	r4, SS_DBAT+0x00(r3)
+	lwz	r5, SS_DBAT+0x04(r3)
+	lwz	r6, SS_DBAT+0x08(r3)
+	lwz	r7, SS_DBAT+0x0c(r3)
+
+	mtspr	SPRN_DBAT0U, r4
+	mtspr	SPRN_DBAT0L, r5
+	mtspr	SPRN_DBAT1U, r6
+	mtspr	SPRN_DBAT1L, r7
+
+	lwz	r4, SS_DBAT+0x10(r3)
+	lwz	r5, SS_DBAT+0x14(r3)
+	lwz	r6, SS_DBAT+0x18(r3)
+	lwz	r7, SS_DBAT+0x1c(r3)
+
+	mtspr	SPRN_DBAT2U, r4
+	mtspr	SPRN_DBAT2L, r5
+	mtspr	SPRN_DBAT3U, r6
+	mtspr	SPRN_DBAT3L, r7
+
+	lwz	r4, SS_DBAT+0x20(r3)
+	lwz	r5, SS_DBAT+0x24(r3)
+	lwz	r6, SS_DBAT+0x28(r3)
+	lwz	r7, SS_DBAT+0x2c(r3)
+
+	mtspr	SPRN_DBAT4U, r4
+	mtspr	SPRN_DBAT4L, r5
+	mtspr	SPRN_DBAT5U, r6
+	mtspr	SPRN_DBAT5L, r7
+
+	lwz	r4, SS_DBAT+0x30(r3)
+	lwz	r5, SS_DBAT+0x34(r3)
+	lwz	r6, SS_DBAT+0x38(r3)
+	lwz	r7, SS_DBAT+0x3c(r3)
+
+	mtspr	SPRN_DBAT6U, r4
+	mtspr	SPRN_DBAT6L, r5
+	mtspr	SPRN_DBAT7U, r6
+	mtspr	SPRN_DBAT7L, r7
+
+	lwz	r4, SS_IBAT+0x00(r3)
+	lwz	r5, SS_IBAT+0x04(r3)
+	lwz	r6, SS_IBAT+0x08(r3)
+	lwz	r7, SS_IBAT+0x0c(r3)
+
+	mtspr	SPRN_IBAT0U, r4
+	mtspr	SPRN_IBAT0L, r5
+	mtspr	SPRN_IBAT1U, r6
+	mtspr	SPRN_IBAT1L, r7
+
+	lwz	r4, SS_IBAT+0x10(r3)
+	lwz	r5, SS_IBAT+0x14(r3)
+	lwz	r6, SS_IBAT+0x18(r3)
+	lwz	r7, SS_IBAT+0x1c(r3)
+
+	mtspr	SPRN_IBAT2U, r4
+	mtspr	SPRN_IBAT2L, r5
+	mtspr	SPRN_IBAT3U, r6
+	mtspr	SPRN_IBAT3L, r7
+
+	lwz	r4, SS_IBAT+0x20(r3)
+	lwz	r5, SS_IBAT+0x24(r3)
+	lwz	r6, SS_IBAT+0x28(r3)
+	lwz	r7, SS_IBAT+0x2c(r3)
+
+	mtspr	SPRN_IBAT4U, r4
+	mtspr	SPRN_IBAT4L, r5
+	mtspr	SPRN_IBAT5U, r6
+	mtspr	SPRN_IBAT5L, r7
+
+	lwz	r4, SS_IBAT+0x30(r3)
+	lwz	r5, SS_IBAT+0x34(r3)
+	lwz	r6, SS_IBAT+0x38(r3)
+	lwz	r7, SS_IBAT+0x3c(r3)
+
+	mtspr	SPRN_IBAT6U, r4
+	mtspr	SPRN_IBAT6L, r5
+	mtspr	SPRN_IBAT7U, r6
+	mtspr	SPRN_IBAT7L, r7
+
+	lwz	r4, SS_SPRG+0(r3)
+	lwz	r5, SS_SPRG+4(r3)
+	lwz	r6, SS_SPRG+8(r3)
+	lwz	r7, SS_SPRG+12(r3)
+	lwz	r8, SS_SDR1(r3)
+
+	mtspr	SPRN_SPRG0, r4
+	mtspr	SPRN_SPRG1, r5
+	mtspr	SPRN_SPRG2, r6
+	mtspr	SPRN_SPRG3, r7
+	mtsdr1	r8
+
+	lwz	r4, SS_MSR(r3)
+	lwz	r5, SS_LR(r3)
+	lwz	r6, SS_CR(r3)
+	lwz	r1, SS_SP(r3)
+	lwz	r2, SS_CURRENT(r3)
+
+	mtsrr1	r4
+	mtsrr0	r5
+	mtcr	r6
+
+	li	r4, 0
+	mtspr	SPRN_TBWL, r4
+
+	lwz	r4, SS_TB+0(r3)
+	lwz	r5, SS_TB+4(r3)
+
+	mtspr	SPRN_TBWU, r4
+	mtspr	SPRN_TBWL, r5
+
+	lmw	r12, SS_GPREG(r3)
+
+	/* Kick decrementer */
+	li	r0, 1
+	mtdec	r0
+
+	rfi
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c
new file mode 100644
index 0000000..61bca38
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/suspend.c
@@ -0,0 +1,423 @@
+/*
+ * MPC83xx suspend support
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/suspend.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/reg.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/mpc6xx.h>
+
+#include <sysdev/fsl_soc.h>
+
+#define PMCCR1_NEXT_STATE       0x0C /* Next state for power management */
+#define PMCCR1_NEXT_STATE_SHIFT 2
+#define PMCCR1_CURR_STATE       0x03 /* Current state for power management*/
+#define IMMR_RCW_OFFSET         0x900
+#define RCW_PCI_HOST            0x80000000
+
+void mpc83xx_enter_deep_sleep(phys_addr_t immrbase);
+
+struct mpc83xx_pmc {
+	u32 config;
+#define PMCCR_DLPEN 2 /* DDR SDRAM low power enable */
+#define PMCCR_SLPEN 1 /* System low power enable */
+
+	u32 event;
+	u32 mask;
+/* All but PMCI are deep-sleep only */
+#define PMCER_GPIO   0x100
+#define PMCER_PCI    0x080
+#define PMCER_USB    0x040
+#define PMCER_ETSEC1 0x020
+#define PMCER_ETSEC2 0x010
+#define PMCER_TIMER  0x008
+#define PMCER_INT1   0x004
+#define PMCER_INT2   0x002
+#define PMCER_PMCI   0x001
+#define PMCER_ALL    0x1FF
+
+	/* deep-sleep only */
+	u32 config1;
+#define PMCCR1_USE_STATE  0x80000000
+#define PMCCR1_PME_EN     0x00000080
+#define PMCCR1_ASSERT_PME 0x00000040
+#define PMCCR1_POWER_OFF  0x00000020
+
+	/* deep-sleep only */
+	u32 config2;
+};
+
+struct mpc83xx_rcw {
+	u32 rcwlr;
+	u32 rcwhr;
+};
+
+struct mpc83xx_clock {
+	u32 spmr;
+	u32 occr;
+	u32 sccr;
+};
+
+struct pmc_type {
+	int has_deep_sleep;
+};
+
+static struct of_device *pmc_dev;
+static int has_deep_sleep, deep_sleeping;
+static int pmc_irq;
+static struct mpc83xx_pmc __iomem *pmc_regs;
+static struct mpc83xx_clock __iomem *clock_regs;
+static int is_pci_agent, wake_from_pci;
+static phys_addr_t immrbase;
+static int pci_pm_state;
+static DECLARE_WAIT_QUEUE_HEAD(agent_wq);
+
+static u32 saved_sccr;
+static DEFINE_SPINLOCK(device_sleep_lock);
+
+void fsl_sleep_device(struct fsl_sleep_platform_data *data)
+{
+	if (clock_regs && data->sccr_mask) {
+		unsigned long flags;
+		u32 sccr;
+
+		spin_lock_irqsave(&device_sleep_lock, flags);
+		sccr = in_be32(&clock_regs->sccr);
+
+		saved_sccr &= ~data->sccr_mask;
+		saved_sccr |= sccr & data->sccr_mask;
+
+		out_be32(&clock_regs->sccr, sccr & ~data->sccr_mask);
+		spin_unlock_irqrestore(&device_sleep_lock, flags);
+	}
+}
+EXPORT_SYMBOL(fsl_sleep_device);
+
+void fsl_wake_device(struct fsl_sleep_platform_data *data)
+{
+	if (clock_regs && data->sccr_mask) {
+		unsigned long flags;
+		u32 sccr;
+
+		spin_lock_irqsave(&device_sleep_lock, flags);
+
+		sccr = in_be32(&clock_regs->sccr);
+		sccr |= saved_sccr & data->sccr_mask;
+		out_be32(&clock_regs->sccr, sccr);
+
+		spin_unlock_irqrestore(&device_sleep_lock, flags);
+	}
+}
+EXPORT_SYMBOL(fsl_wake_device);
+
+int fsl_deep_sleep(void)
+{
+	return deep_sleeping;
+}
+
+static int mpc83xx_change_state(void)
+{
+	u32 curr_state;
+	u32 reg_cfg1 = in_be32(&pmc_regs->config1);
+
+	if (is_pci_agent) {
+		pci_pm_state = (reg_cfg1 & PMCCR1_NEXT_STATE) >>
+		               PMCCR1_NEXT_STATE_SHIFT;
+		curr_state = reg_cfg1 & PMCCR1_CURR_STATE;
+
+		if (curr_state != pci_pm_state) {
+			reg_cfg1 &= ~PMCCR1_CURR_STATE;
+			reg_cfg1 |= pci_pm_state;
+			out_be32(&pmc_regs->config1, reg_cfg1);
+
+			wake_up(&agent_wq);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t pmc_irq_handler(int irq, void *dev_id)
+{
+	u32 event = in_be32(&pmc_regs->event);
+	int ret = IRQ_NONE;
+
+	if (mpc83xx_change_state())
+		ret = IRQ_HANDLED;
+
+	if (event) {
+		out_be32(&pmc_regs->event, event);
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int mpc83xx_suspend_enter(suspend_state_t state)
+{
+	int ret = -EAGAIN;
+
+	/* Don't go to sleep if there's a race where pci_pm_state changes
+	 * between the agent thread checking it and the PM code disabling
+	 * interrupts.
+	 */
+	if (wake_from_pci) {
+		if (pci_pm_state != (deep_sleeping ? 3 : 2))
+			goto out;
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) | PMCCR1_PME_EN);
+	}
+
+	/* Put the system into low-power mode and the RAM
+	 * into self-refresh mode once the core goes to
+	 * sleep.
+	 */
+
+	out_be32(&pmc_regs->config, PMCCR_SLPEN | PMCCR_DLPEN);
+
+	/* If it has deep sleep (i.e. it's an 831x or compatible),
+	 * disable power to the core upon entering sleep mode.  This will
+	 * require going through the boot firmware upon a wakeup event.
+	 */
+
+	if (deep_sleeping) {
+		out_be32(&pmc_regs->mask, PMCER_ALL);
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) | PMCCR1_POWER_OFF);
+
+		enable_kernel_fp();
+
+		mpc83xx_enter_deep_sleep(immrbase);
+
+		out_be32(&pmc_regs->config1,
+		         in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF);
+
+		out_be32(&pmc_regs->mask, PMCER_PMCI);
+	} else {
+		out_be32(&pmc_regs->mask, PMCER_PMCI);
+
+		mpc6xx_enter_standby();
+	}
+
+	ret = 0;
+
+out:
+	out_be32(&pmc_regs->config1,
+	         in_be32(&pmc_regs->config1) & ~PMCCR1_PME_EN);
+
+	return ret;
+}
+
+static void mpc83xx_suspend_finish(void)
+{
+	deep_sleeping = 0;
+}
+
+static int mpc83xx_suspend_valid(suspend_state_t state)
+{
+	return state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM;
+}
+
+static int mpc83xx_suspend_set_target(suspend_state_t state)
+{
+	switch (state) {
+		case PM_SUSPEND_STANDBY:
+			deep_sleeping = 0;
+			return 0;
+
+		case PM_SUSPEND_MEM:
+			if (has_deep_sleep)
+				deep_sleeping = 1;
+
+			return 0;
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int agent_thread_fn(void *data)
+{
+	while (1) {
+		wait_event_interruptible(agent_wq, pci_pm_state >= 2);
+		try_to_freeze();
+
+		if (signal_pending(current) || pci_pm_state < 2)
+			continue;
+
+		/* With a preemptible kernel (or SMP), this could race with a
+		 * userspace-driven suspend request.  It's probably best to
+		 * avoid mixing the two with such a configuration (or else fix
+		 * it by adding a mutex to state_store that we can synchronize
+		 * with).
+		 */
+
+		wake_from_pci = 1;
+
+		pm_suspend(pci_pm_state == 3 ? PM_SUSPEND_MEM :
+		                               PM_SUSPEND_STANDBY);
+
+		wake_from_pci = 0;
+	}
+
+	return 0;
+}
+
+void mpc83xx_set_agent(void)
+{
+	out_be32(&pmc_regs->config1, PMCCR1_USE_STATE);
+	out_be32(&pmc_regs->mask, PMCER_PMCI);
+
+	kthread_run(agent_thread_fn, NULL, "PCI power mgt");
+}
+
+static int mpc83xx_is_pci_agent(void)
+{
+	struct mpc83xx_rcw __iomem *rcw_regs;
+	int ret;
+
+	rcw_regs = ioremap(get_immrbase() + IMMR_RCW_OFFSET,
+	                   sizeof(struct mpc83xx_rcw));
+
+	if (!rcw_regs)
+		return -ENOMEM;
+
+	ret = !(in_be32(&rcw_regs->rcwhr) & RCW_PCI_HOST);
+
+	iounmap(rcw_regs);
+	return ret;
+}
+
+static struct platform_suspend_ops mpc83xx_suspend_ops = {
+	.valid = mpc83xx_suspend_valid,
+	.set_target = mpc83xx_suspend_set_target,
+	.enter = mpc83xx_suspend_enter,
+	.finish = mpc83xx_suspend_finish,
+};
+
+static int pmc_probe(struct of_device *ofdev,
+                     const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct resource res;
+	struct pmc_type *type = match->data;
+	int ret = 0;
+
+	has_deep_sleep = type->has_deep_sleep;
+	immrbase = get_immrbase();
+	pmc_dev = ofdev;
+
+	is_pci_agent = mpc83xx_is_pci_agent();
+	if (is_pci_agent < 0)
+		return is_pci_agent;
+
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		return -ENODEV;
+
+	pmc_irq = irq_of_parse_and_map(np, 0);
+	if (pmc_irq != NO_IRQ) {
+		ret = request_irq(pmc_irq, pmc_irq_handler, IRQF_SHARED,
+		                  "pmc", ofdev);
+
+		if (ret)
+			return -EBUSY;
+	}
+
+	pmc_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc));
+
+	if (!pmc_regs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = of_address_to_resource(np, 1, &res);
+	if (ret) {
+		ret = -ENODEV;
+		goto out_pmc;
+	}
+
+	clock_regs = ioremap(res.start, sizeof(struct mpc83xx_pmc));
+
+	if (!clock_regs) {
+		ret = -ENOMEM;
+		goto out_pmc;
+	}
+
+	if (is_pci_agent)
+		mpc83xx_set_agent();
+
+	suspend_set_ops(&mpc83xx_suspend_ops);
+	return 0;
+
+out_pmc:
+	iounmap(pmc_regs);
+out:
+	if (pmc_irq != NO_IRQ)
+		free_irq(pmc_irq, ofdev);
+
+	return ret;
+}
+
+static int pmc_remove(struct of_device *ofdev)
+{
+	return -EPERM;
+};
+
+static struct pmc_type pmc_types[] = {
+	{
+		.has_deep_sleep = 1,
+	},
+	{
+		.has_deep_sleep = 0,
+	}
+};
+
+static struct of_device_id pmc_match[] = {
+	{
+		.compatible = "fsl,mpc8313-pmc",
+		.data = &pmc_types[0],
+	},
+	{
+		.compatible = "fsl,mpc8349-pmc",
+		.data = &pmc_types[1],
+	},
+	{}
+};
+
+static struct of_platform_driver pmc_driver = {
+	.name = "mpc83xx-pmc",
+	.match_table = pmc_match,
+	.probe = pmc_probe,
+	.remove = pmc_remove
+};
+
+static int pmc_init(void)
+{
+	return of_register_platform_driver(&pmc_driver);
+}
+
+module_init(pmc_init);
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index e1ba33c..d5fd916 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -207,6 +207,33 @@ static int __init of_add_fixed_phys(void)
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
+int fsl_sleep_init(struct fsl_sleep_platform_data *sleep,
+                   struct device_node *node)
+{
+	int proplen, ret = -ENODEV;
+	const u32 *sleepdata = of_get_property(node, "sleep", &proplen);
+	struct device_node *sleep_controller;
+
+	if (!sleepdata || proplen != 8)
+		return -ENODEV;
+
+	sleep_controller = of_find_node_by_phandle(sleepdata[0]);
+	if (!sleep_controller)
+		return -ENODEV;
+
+	/* There can only be one fsl,mpc83xx-pmc device in the system;
+	 * it is assumed that it is the one that the pmc driver matches.
+	 */
+	if (of_device_is_compatible(sleep_controller, "fsl,mpc83xx-pmc")) {
+		sleep->sccr_mask = sleepdata[1];
+		ret = 0;
+	}
+
+	of_node_put(sleep_controller);
+	return ret;
+}
+EXPORT_SYMBOL(fsl_sleep_init);
+
 static int __init gfar_mdio_of_init(void)
 {
 	struct device_node *np = NULL;
@@ -396,6 +423,8 @@ static int __init gfar_of_init(void)
 			of_node_put(mdio);
 		}
 
+		fsl_sleep_init(&gfar_data.sleep, np);
+
 		ret =
 		    platform_device_add_data(gfar_dev, &gfar_data,
 					     sizeof(struct
@@ -647,6 +676,8 @@ static int __init fsl_usb_of_init(void)
 		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
+		fsl_sleep_init(&usb_data.sleep, np);
+
 		ret =
 		    platform_device_add_data(usb_dev_mph, &usb_data,
 					     sizeof(struct
@@ -710,6 +741,8 @@ static int __init fsl_usb_of_init(void)
 		prop = of_get_property(np, "phy_type", NULL);
 		usb_data.phy_mode = determine_usb_phy(prop);
 
+		fsl_sleep_init(&usb_data.sleep, np);
+
 		if (usb_dev_dr_host) {
 			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
 			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 74c4a96..fb52d39 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -10,12 +10,22 @@ extern u32 get_baudrate(void);
 extern u32 fsl_get_sys_freq(void);
 
 struct spi_board_info;
+struct fsl_sleep_platform_data;
+struct device_node;
 
 extern int fsl_spi_init(struct spi_board_info *board_infos,
 			unsigned int num_board_infos,
 			void (*activate_cs)(u8 cs, u8 polarity),
 			void (*deactivate_cs)(u8 cs, u8 polarity));
 
+int fsl_sleep_init(struct fsl_sleep_platform_data *sleep,
+                   struct device_node *node);
+
+/* Calls to fsl_sleep_dev and fsl_wake_dev cannot be nested. */
+void fsl_sleep_dev(struct fsl_sleep_platform_data *sleep);
+void fsl_wake_dev(struct fsl_sleep_platform_data *sleep);
+
 extern void fsl_rstcr_restart(char *cmd);
+
 #endif
 #endif
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 05a56e5..e2388cf 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -22,6 +22,7 @@
 #include <linux/device.h>
 #include <linux/bootmem.h>
 #include <linux/spinlock.h>
+#include <linux/fsl_devices.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -893,8 +894,78 @@ unsigned int ipic_get_irq(void)
 	return irq_linear_revmap(primary_ipic->irqhost, irq);
 }
 
+#ifdef CONFIG_PM
+static struct {
+	u32 sicfr;
+	u32 siprr[2];
+	u32 simsr[2];
+	u32 sicnr;
+	u32 smprr[2];
+	u32 semsr;
+	u32 secnr;
+	u32 sermr;
+	u32 sercr;
+} ipic_saved_state;
+
+static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+{
+	struct ipic *ipic = primary_ipic;
+
+	ipic_saved_state.sicfr = ipic_read(ipic->regs, IPIC_SICFR);
+	ipic_saved_state.siprr[0] = ipic_read(ipic->regs, IPIC_SIPRR_A);
+	ipic_saved_state.siprr[1] = ipic_read(ipic->regs, IPIC_SIPRR_D);
+	ipic_saved_state.simsr[0] = ipic_read(ipic->regs, IPIC_SIMSR_H);
+	ipic_saved_state.simsr[1] = ipic_read(ipic->regs, IPIC_SIMSR_L);
+	ipic_saved_state.sicnr = ipic_read(ipic->regs, IPIC_SICNR);
+	ipic_saved_state.smprr[0] = ipic_read(ipic->regs, IPIC_SMPRR_A);
+	ipic_saved_state.smprr[1] = ipic_read(ipic->regs, IPIC_SMPRR_B);
+	ipic_saved_state.semsr = ipic_read(ipic->regs, IPIC_SEMSR);
+	ipic_saved_state.secnr = ipic_read(ipic->regs, IPIC_SECNR);
+	ipic_saved_state.sermr = ipic_read(ipic->regs, IPIC_SERMR);
+	ipic_saved_state.sercr = ipic_read(ipic->regs, IPIC_SERCR);
+
+	if (fsl_deep_sleep()) {
+		/* In deep sleep, make sure there can be no
+		 * pending interrupts, as this can cause
+		 * problems on 831x.
+		 */
+		ipic_write(ipic->regs, IPIC_SIMSR_H, 0);
+		ipic_write(ipic->regs, IPIC_SIMSR_L, 0);
+		ipic_write(ipic->regs, IPIC_SEMSR, 0);
+		ipic_write(ipic->regs, IPIC_SERMR, 0);
+	}
+
+	return 0;
+}
+
+static int ipic_resume(struct sys_device *sdev)
+{
+	struct ipic *ipic = primary_ipic;
+
+	ipic_write(ipic->regs, IPIC_SICFR, ipic_saved_state.sicfr);
+	ipic_write(ipic->regs, IPIC_SIPRR_A, ipic_saved_state.siprr[0]);
+	ipic_write(ipic->regs, IPIC_SIPRR_D, ipic_saved_state.siprr[1]);
+	ipic_write(ipic->regs, IPIC_SIMSR_H, ipic_saved_state.simsr[0]);
+	ipic_write(ipic->regs, IPIC_SIMSR_L, ipic_saved_state.simsr[1]);
+	ipic_write(ipic->regs, IPIC_SICNR, ipic_saved_state.sicnr);
+	ipic_write(ipic->regs, IPIC_SMPRR_A, ipic_saved_state.smprr[0]);
+	ipic_write(ipic->regs, IPIC_SMPRR_B, ipic_saved_state.smprr[1]);
+	ipic_write(ipic->regs, IPIC_SEMSR, ipic_saved_state.semsr);
+	ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
+	ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
+	ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
+
+	return 0;
+}
+#else
+#define ipic_suspend NULL
+#define ipic_resume NULL
+#endif
+
 static struct sysdev_class ipic_sysclass = {
 	.name = "ipic",
+	.suspend = ipic_suspend,
+	.resume = ipic_resume,
 };
 
 static struct sys_device device_ipic = {
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 1f68504..68968c1 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -153,10 +153,12 @@
 #define   CTRL_RUNLATCH	0x1
 #define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
 #define   DABR_TRANSLATION	(1UL << 2)
+#define SPRN_DABR2	0x13D	/* 83xx */
 #define SPRN_DABRX	0x3F7	/* Data Address Breakpoint Register Extension */
 #define   DABRX_USER	(1UL << 0)
 #define   DABRX_KERNEL	(1UL << 1)
 #define SPRN_DAR	0x013	/* Data Address Register */
+#define SPRN_DBCR	0x136	/* 83xx Data Breakpoint Control Reg */
 #define SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
 #define   DSISR_NOHPTE		0x40000000	/* no translation found */
 #define   DSISR_PROTFAULT	0x08000000	/* protection fault */
@@ -262,6 +264,8 @@
 #define HID1_PS		(1<<16)		/* 750FX PLL selection */
 #define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */
 #define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#define SPRN_IABR2	0x3FA		/* 83xx */
+#define SPRN_IBCR	0x135		/* 83xx Insn Breakpoint Control Reg */
 #define SPRN_HID4	0x3F4		/* 970 HID4 */
 #define SPRN_HID5	0x3F6		/* 970 HID5 */
 #define SPRN_HID6	0x3F9	/* BE HID 6 */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 1831b19..5cec939 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -45,10 +45,27 @@
  *
  */
 
+struct fsl_sleep_platform_data {
+	/*
+	 * The bits set in this mask will be cleared in the SCCR
+	 * when put to sleep, and restored on wakeup.
+	 */
+	u32 sccr_mask;
+};
+
+/*
+ * Calls to fsl_sleep_device do not nest -- if you call
+ * sleep twice without an intervening wake, you will not
+ * be able to wake the device again.
+ */
+void fsl_sleep_device(struct fsl_sleep_platform_data *data);
+void fsl_wake_device(struct fsl_sleep_platform_data *data);
+
 struct gianfar_platform_data {
 	/* device specific information */
 	u32	device_flags;
 	/* board specific information */
+	struct fsl_sleep_platform_data sleep;
 	u32	board_flags;
 	char	bus_id[MII_BUS_ID_SIZE];
 	u32	phy_id;
@@ -104,6 +121,7 @@ struct fsl_usb2_platform_data {
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
+	struct fsl_sleep_platform_data sleep;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
@@ -126,5 +144,11 @@ struct mpc8xx_pcmcia_ops {
 	int(*voltage_set)(int slot, int vcc, int vpp);
 };
 
+/* Returns non-zero if the current suspend operation would
+ * lead to a deep sleep (i.e. power removed from the core,
+ * instead of just the clock).
+ */
+int fsl_deep_sleep(void);
+
 #endif /* _FSL_DEVICE_H_ */
 #endif /* __KERNEL__ */
-- 
1.5.3.7

^ permalink raw reply related

* [PATCH 4/7] mpc83xx: timer driver for PM wakeup
From: Guennadi Liakhovetski @ 2008-04-28 15:39 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

This is a driver for the mpc83xx's GTM4 timer.  It's functionality
is limited to providing a wakeup source for suspend-to-RAM.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 arch/powerpc/platforms/83xx/Kconfig  |    9 +
 arch/powerpc/platforms/83xx/Makefile |    1 +
 arch/powerpc/platforms/83xx/timer.c  |  299 ++++++++++++++++++++++++++++++++++
 3 files changed, 309 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/83xx/timer.c

diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 901dbaf..800f547 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -80,6 +80,15 @@ config PPC_83xx_SUSPEND
 	  This option enables support for the Wind River SBC834x board.
 
 endif
+
+config MPC83xx_GTM
+	tristate "83xx General-Purpose Timers for PM wakeup"
+	help
+	  This enables a driver for the GTM4 timer, to be used
+	  as a wakeup source for suspend-to-RAM.  To arm the
+	  timer, write the number of seconds until expiration
+	  to the "timeout" file in the device's sysfs directory.
+	  To disarm, write 0 to the "timeout" file.
 
 # used for usb
 config PPC_MPC831x
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 944369e..bcc1003 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@
 obj-y				:= misc.o usb.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o suspend-asm.o
+obj-$(CONFIG_MPC83xx_GTM)	+= timer.o
 obj-$(CONFIG_MPC831x_RDB)	+= mpc831x_rdb.o
 obj-$(CONFIG_MPC832x_RDB)	+= mpc832x_rdb.o
 obj-$(CONFIG_MPC834x_MDS)	+= mpc834x_mds.o
diff --git a/arch/powerpc/platforms/83xx/timer.c b/arch/powerpc/platforms/83xx/timer.c
new file mode 100644
index 0000000..7fc6048
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/timer.c
@@ -0,0 +1,300 @@
+/*
+ * MPC83xx Global Timer4 support
+ *
+ * This driver is currently specific to timer 4 in 16-bit mode,
+ * as that is all that can be used as a wakeup source for deep sleep
+ * on the MPC8313.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <sysdev/fsl_soc.h>
+
+#define MDR_ICLK_DIV16	0x0004
+
+struct gtm_regs {
+	u8    cfr1; /* Timer1/2 Configuration  */
+	#define CFR1_PCAS 0x80 /* Pair Cascade mode  */
+	#define CFR1_BCM  0x40  /* Backward compatible mode  */
+	#define CFR1_STP2 0x20 /* Stop timer  */
+	#define CFR1_RST2 0x10 /* Reset timer  */
+	#define CFR1_GM2  0x08 /* Gate mode for pin 2  */
+	#define CFR1_GM1  0x04 /* Gate mode for pin 1  */
+	#define CFR1_STP1 0x02 /* Stop timer  */
+	#define CFR1_RST1 0x01 /* Reset timer  */
+	#define CFR1_RES ~(CFR1_PCAS | CFR1_STP2 | CFR1_RST2 | CFR1_GM2 |\
+		CFR1_GM1 | CFR1_STP1 | CFR1_RST1)
+
+	u8    res0[3];
+	u8    cfr2; /* Timer3/4 Configuration  */
+	#define CFR2_PCAS 0x80 /* Pair Cascade mode  */
+	#define CFR2_SCAS 0x40 /* Super Cascade mode  */
+	#define CFR2_STP4 0x20 /* Stop timer  */
+	#define CFR2_RST4 0x10 /* Reset timer  */
+	#define CFR2_GM4  0x08 /* Gate mode for pin 4  */
+	#define CFR2_GM3  0x04 /* Gate mode for pin 3  */
+	#define CFR2_STP3 0x02 /* Stop timer  */
+	#define CFR2_RST3 0x01 /* Reset timer  */
+
+	u8    res1[11];
+	u16   mdr1; /* Timer1 Mode Register  */
+	#define MDR_SPS  0xff00 /* Secondary Prescaler value (256) */
+	#define MDR_CE   0x00c0 /* Capture edge and enable interrupt  */
+	#define MDR_OM   0x0020 /* Output mode  */
+	#define MDR_ORI  0x0010 /* Output reference interrupt enable  */
+	#define MDR_FRR  0x0008 /* Free run/restart  */
+	#define MDR_ICLK 0x0006 /* Input clock source for the timer */
+	#define MDR_GE   0x0001 /* Gate enable  */
+
+	u16   mdr2; /* Timer2 Mode Register  */
+	u16   rfr1; /* Timer1 Reference Register  */
+	u16   rfr2; /* Timer2 Reference Register  */
+	u16   cpr1; /* Timer1 Capture Register  */
+	u16   cpr2; /* Timer2 Capture Register  */
+	u16   cnr1; /* Timer1 Counter Register  */
+	u16   cnr2; /* Timer2 Counter Register  */
+	u16   mdr3; /* Timer3 Mode Register  */
+	u16   mdr4; /* Timer4 Mode Register  */
+	u16   rfr3; /* Timer3 Reference Register  */
+	u16   rfr4; /* Timer4 Reference Register  */
+	u16   cpr3; /* Timer3 Capture Register  */
+	u16   cpr4; /* Timer4 Capture Register  */
+	u16   cnr3; /* Timer3 Counter Register  */
+	u16   cnr4; /* Timer4 Counter Register  */
+	u16   evr1; /* Timer1 Event Register  */
+	u16   evr2; /* Timer2 Event Register  */
+	u16   evr3; /* Timer3 Event Register  */
+	u16   evr4; /* Timer4 Event Register  */
+	#define GTEVR_REF 0x0002 /* Output reference event  */
+	#define GTEVR_CAP 0x0001 /* Counter Capture event   */
+	#define GTEVR_RES ~(EVR_CAP|EVR_REF)
+
+	u16   psr1; /* Timer1 Prescaler Register  */
+	u16   psr2; /* Timer2 Prescaler Register  */
+	u16   psr3; /* Timer3 Prescaler Register  */
+	u16   psr4; /* Timer4 Prescaler Register  */
+	#define GTPSR_PPS  0x00FF /* Primary Prescaler Bits (256). */
+	#define GTPSR_RES  ~(GTPSR_PPS)
+};
+
+struct gtm_priv {
+	struct gtm_regs __iomem *regs;
+	int irq;
+	int ticks_per_sec;
+	spinlock_t lock;
+};
+
+static irqreturn_t fsl_gtm_isr(int irq, void *dev_id)
+{
+	struct gtm_priv *priv = dev_id;
+	unsigned long flags;
+	u16 event;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	event = in_be16(&priv->regs->evr4);
+	out_be16(&priv->regs->evr4, event);
+
+	if (event & GTEVR_REF)
+		out_8(&priv->regs->cfr2, CFR2_STP4);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return event ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static ssize_t gtm_timeout_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+	struct gtm_priv *priv = dev_get_drvdata(dev);
+	unsigned long interval = simple_strtoul(buf, NULL, 0);
+
+	if (interval > 0xffff) {
+		dev_dbg(dev, "gtm: interval %lu (in ns) too long\n", interval);
+		return -EINVAL;
+	}
+
+	interval *= priv->ticks_per_sec;
+
+	if (interval > 0xffff) {
+		dev_dbg(dev, "gtm: interval %lu (in ticks) too long\n",
+		        interval);
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&priv->lock);
+
+	/* reset timer 4 */
+	out_8(&priv->regs->cfr2, CFR2_STP3 | CFR2_STP4);
+
+	if (interval != 0) {
+		out_8(&priv->regs->cfr2, CFR2_GM4 | CFR2_RST4 | CFR2_STP4);
+		/* clear events */
+		out_be16(&priv->regs->evr4, GTEVR_REF | GTEVR_CAP);
+		/* maximum primary prescale (256) */
+		out_be16(&priv->regs->psr4, GTPSR_PPS);
+		/* clear current counter */
+		out_be16(&priv->regs->cnr4, 0x0);
+		/* set count limit */
+		out_be16(&priv->regs->rfr4, interval);
+		out_be16(&priv->regs->mdr4, MDR_SPS | MDR_ORI | MDR_FRR |
+		                            MDR_ICLK_DIV16);
+		/* start timer */
+		out_8(&priv->regs->cfr2, CFR2_GM4 | CFR2_STP3 | CFR2_RST4);
+	}
+
+	spin_unlock_irq(&priv->lock);
+	return count;
+}
+
+static ssize_t gtm_timeout_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+	struct gtm_priv *priv = dev_get_drvdata(dev);
+	int timeout = 0;
+
+	spin_lock_irq(&priv->lock);
+
+	if (!(in_8(&priv->regs->cfr2) & CFR2_STP4)) {
+		timeout = in_be16(&priv->regs->rfr4) -
+		          in_be16(&priv->regs->cnr4);
+		timeout += priv->ticks_per_sec - 1;
+		timeout /= priv->ticks_per_sec;
+	}
+
+	spin_unlock_irq(&priv->lock);
+	return sprintf(buf, "%u\n", timeout);
+}
+
+static DEVICE_ATTR(timeout, 0660, gtm_timeout_show, gtm_timeout_store);
+
+static int __devinit gtm_probe(struct of_device *dev,
+                               const struct of_device_id *match)
+{
+	struct device_node *np = dev->node;
+	struct resource res;
+	int ret = 0;
+	u32 busfreq = fsl_get_sys_freq();
+	struct gtm_priv *priv;
+
+	if (busfreq == 0) {
+		dev_err(&dev->dev, "gtm: No bus frequency in device tree.\n");
+		return -ENODEV;
+	}
+
+	priv = kmalloc(sizeof(struct gtm_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	spin_lock_init(&priv->lock);
+	dev_set_drvdata(&dev->dev, priv);
+
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		goto out;
+
+	priv->irq = irq_of_parse_and_map(np, 0);
+	if (priv->irq == NO_IRQ) {
+		dev_err(&dev->dev, "mpc83xx-gtm exists in device tree "
+		                   "without an IRQ.\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = request_irq(priv->irq, fsl_gtm_isr, 0, "gtm timer", priv);
+	if (ret)
+		goto out;
+
+	priv->regs = ioremap(res.start, sizeof(struct gtm_regs));
+	if (!priv->regs) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Disable the unused clocks to save power. */
+	out_8(&priv->regs->cfr1, CFR1_STP1 | CFR1_STP2);
+	out_8(&priv->regs->cfr2, CFR2_STP3 | CFR2_STP4);
+
+	/*
+	 * Maximum prescaling is used (input clock/16, 256 primary prescaler,
+	 * 256 secondary prescaler) to maximize the timer's range.  With a
+	 * bus clock of 133MHz, this yields a maximum interval of 516
+	 * seconds while retaining subsecond precision.  Since only
+	 * timer 4 is supported for wakeup on the 8313, and timer 4
+	 * is the LSB when chained, we can't use chaining to increase
+	 * the range.
+	 */
+	priv->ticks_per_sec = busfreq / (16*256*256);
+
+	ret = device_create_file(&dev->dev, &dev_attr_timeout);
+	if (ret)
+		goto out;
+
+	return 0;
+
+out:
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(priv);
+	return ret;
+}
+
+static int __devexit gtm_remove(struct of_device *dev)
+{
+	struct gtm_priv *priv = dev_get_drvdata(&dev->dev);
+
+	device_remove_file(&dev->dev, &dev_attr_timeout);
+	free_irq(priv->irq, priv);
+	iounmap(priv->regs);
+
+	dev_set_drvdata(&dev->dev, NULL);
+	kfree(priv);
+	return 0;
+}
+
+static struct of_device_id gtm_match[] = {
+	{
+		.compatible = "fsl,mpc8313-gtm",
+	},
+	{},
+};
+
+static struct of_platform_driver gtm_driver = {
+	.name = "mpc83xx-gtm",
+	.match_table = gtm_match,
+	.probe = gtm_probe,
+	.remove = __devexit_p(gtm_remove)
+};
+
+static int __init gtm_init(void)
+{
+	return of_register_platform_driver(&gtm_driver);
+}
+
+static void __exit gtm_exit(void)
+{
+	of_unregister_platform_driver(&gtm_driver);
+}
+
+module_init(gtm_init);
+module_exit(gtm_exit);
-- 
1.5.3.7

^ permalink raw reply related

* [PATCH 5/7] gianfar: Add flags for magic packet and MDIO.
From: Guennadi Liakhovetski @ 2008-04-28 15:39 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, linux-pm, Paul Mackerras
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

The magic packet flag indicates that the hardware has this
capability.  The MDIO flag indicates that this device's
registers contain active MDIO registers, and thus this
device should not be put to sleep.

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
 arch/powerpc/sysdev/fsl_soc.c |    7 +++++++
 include/linux/fsl_devices.h   |    2 ++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index d5fd916..032b8e8 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -324,6 +324,9 @@ static int __init gfar_of_init(void)
 		else
 			gfar_data.interface = PHY_INTERFACE_MODE_MII;
 
+		if (of_get_property(np, "fsl,magic-packet", NULL))
+			gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
+
 		ph = of_get_property(np, "phy-handle", NULL);
 		if (ph == NULL) {
 			u32 *fixed_link;
@@ -345,6 +348,10 @@ static int __init gfar_of_init(void)
 			snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%x",
 					res.start);
 
+			if (res.start >= gfar_dev->resource[0].start &&
+			    res.start < gfar_dev->resource[0].end)
+				gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MDIO;
+
 			of_node_put(phy);
 			of_node_put(mdio);
 		}
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 5cec939..81fcc67 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -87,6 +87,8 @@ struct gianfar_mdio_data {
 #define FSL_GIANFAR_DEV_HAS_VLAN		0x00000020
 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH	0x00000040
 #define FSL_GIANFAR_DEV_HAS_PADDING		0x00000080
+#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET	0x00000100
+#define FSL_GIANFAR_DEV_HAS_MDIO		0x00000200
 
 /* Flags in gianfar_platform_data */
 #define FSL_GIANFAR_BRD_HAS_PHY_INTR	0x00000001 /* set or use a timer */
-- 
1.5.3.7

^ permalink raw reply related

* [PATCH 6/7] gianfar: Magic Packet and suspend/resume support.
From: Guennadi Liakhovetski @ 2008-04-28 15:40 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, jgarzik, linux-pm, Paul Mackerras, netdev
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

This patch has already been acked by Jeff Garzik:

>From jgarzik@pobox.com Fri Dec 14 20:28:38 2007
Date: Fri, 14 Dec 2007 15:24:29 -0500
From: Jeff Garzik <jgarzik@pobox.com>
To: Scott Wood <scottwood@freescale.com>
Cc: linuxppc-dev@ozlabs.org, paulus@samba.org, netdev@vger.kernel.org
Subject: Re: [PATCH 8/8] gianfar: Magic Packet and suspend/resume support.

Scott Wood wrote:
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> Jeff, can you ack this to go through Paul's tree
> (assuming nothing wrong with it)?
> 
>  drivers/net/gianfar.c         |  137 ++++++++++++++++++++++++++++++++++++++++-
>  drivers/net/gianfar.h         |   13 +++-
>  drivers/net/gianfar_ethtool.c |   41 ++++++++++++-
>  3 files changed, 185 insertions(+), 6 deletions(-)

ACK

 drivers/net/gianfar.c         |  137 ++++++++++++++++++++++++++++++++++++++++-
 drivers/net/gianfar.h         |   13 +++-
 drivers/net/gianfar_ethtool.c |   41 ++++++++++++-
 3 files changed, 185 insertions(+), 6 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 0431e9e..2c1b8d5 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -142,6 +142,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
 static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
 static void gfar_vlan_rx_register(struct net_device *netdev,
 		                struct vlan_group *grp);
+static void gfar_halt_nodisable(struct net_device *dev);
 void gfar_halt(struct net_device *dev);
 void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
@@ -216,6 +217,7 @@ static int gfar_probe(struct platform_device *pdev)
 
 	spin_lock_init(&priv->txlock);
 	spin_lock_init(&priv->rxlock);
+	spin_lock_init(&priv->bflock);
 
 	platform_set_drvdata(pdev, dev);
 
@@ -393,6 +395,122 @@ static int gfar_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int gfar_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	u32 tempval;
+
+	int magic_packet = priv->wol_en &&
+		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+
+	netif_device_detach(dev);
+
+	if (netif_running(dev)) {
+		spin_lock_irqsave(&priv->txlock, flags);
+		spin_lock(&priv->rxlock);
+
+		gfar_halt_nodisable(dev);
+
+		/* Disable Tx, and Rx if wake-on-LAN is disabled. */
+		tempval = gfar_read(&priv->regs->maccfg1);
+
+		tempval &= ~MACCFG1_TX_EN;
+
+		if (!magic_packet)
+			tempval &= ~MACCFG1_RX_EN;
+
+		gfar_write(&priv->regs->maccfg1, tempval);
+
+		spin_unlock(&priv->rxlock);
+		spin_unlock_irqrestore(&priv->txlock, flags);
+
+#ifdef CONFIG_GFAR_NAPI
+		napi_disable(&priv->napi);
+#endif
+
+		if (magic_packet) {
+			/* Enable interrupt on Magic Packet */
+			gfar_write(&priv->regs->imask, IMASK_MAG);
+
+			/* Enable Magic Packet mode */
+			tempval = gfar_read(&priv->regs->maccfg2);
+			tempval |= MACCFG2_MPEN;
+			gfar_write(&priv->regs->maccfg2, tempval);
+		} else {
+			phy_stop(priv->phydev);
+		}
+	}
+
+	if (!magic_packet || !netif_running(dev)) {
+		/* The device with the MDIO in its register block must
+		 * not be put to sleep if any other network devices
+		 * using the same MDIO are active.  Ideally, some sort
+		 * of reference counting could be done, but for now
+		 * just don't put the MDIO-containing dev to sleep
+		 * at all.
+		 */
+		if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MDIO)) {
+			fsl_sleep_device(&priv->einfo->sleep);
+			priv->suspended = 1;
+		}
+	}
+
+	return 0;
+}
+
+static int gfar_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
+	u32 tempval;
+	int magic_packet = priv->wol_en &&
+		(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
+
+	if (priv->suspended) {
+		fsl_wake_device(&priv->einfo->sleep);
+		priv->suspended = 0;
+	}
+
+	if (!netif_running(dev)) {
+		netif_device_attach(dev);
+		return 0;
+	}
+
+	if (!magic_packet && priv->phydev)
+		phy_start(priv->phydev);
+
+	/* Disable Magic Packet mode, in case something
+	 * else woke us up.
+	 */
+
+	spin_lock_irqsave(&priv->txlock, flags);
+	spin_lock(&priv->rxlock);
+
+	tempval = gfar_read(&priv->regs->maccfg2);
+	tempval &= ~MACCFG2_MPEN;
+	gfar_write(&priv->regs->maccfg2, tempval);
+
+	gfar_start(dev);
+
+	spin_unlock(&priv->rxlock);
+	spin_unlock_irqrestore(&priv->txlock, flags);
+
+	netif_device_attach(dev);
+
+#ifdef CONFIG_GFAR_NAPI
+	napi_enable(&priv->napi);
+#endif
+
+	return 0;
+}
+#else
+#define gfar_suspend NULL
+#define gfar_resume NULL
+#endif
 
 /* Reads the controller's registers to determine what interface
  * connects it to the PHY.
@@ -547,7 +665,7 @@ static void init_registers(struct net_device *dev)
 
 
 /* Halt the receive and transmit queues */
-void gfar_halt(struct net_device *dev)
+static void gfar_halt_nodisable(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 	struct gfar __iomem *regs = priv->regs;
@@ -570,6 +688,14 @@ void gfar_halt(struct net_device *dev)
 			 (IEVENT_GRSC | IEVENT_GTSC)))
 			cpu_relax();
 	}
+}
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	struct gfar __iomem *regs = priv->regs;
+	u32 tempval;
 
 	/* Disable Rx and Tx */
 	tempval = gfar_read(&regs->maccfg1);
@@ -1909,7 +2035,12 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
 	u32 events = gfar_read(&priv->regs->ievent);
 
 	/* Clear IEVENT */
-	gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
+	gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK);
+
+	/* Magic Packet is not an error. */
+	if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
+	    (events & IEVENT_MAG))
+		events &= ~IEVENT_MAG;
 
 	/* Hmm... */
 	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
@@ -1979,6 +2110,8 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
 static struct platform_driver gfar_driver = {
 	.probe = gfar_probe,
 	.remove = gfar_remove,
+	.suspend = gfar_suspend,
+	.resume = gfar_resume,
 	.driver	= {
 		.name = "fsl-gianfar",
 	},
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 46cd773..922ed36 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -162,6 +162,7 @@ extern const char gfar_driver_version[];
 #define MACCFG2_GMII            0x00000200
 #define MACCFG2_HUGEFRAME	0x00000020
 #define MACCFG2_LENGTHCHECK	0x00000010
+#define MACCFG2_MPEN		0x00000008
 
 #define ECNTRL_INIT_SETTINGS	0x00001000
 #define ECNTRL_TBI_MODE         0x00000020
@@ -234,6 +235,7 @@ extern const char gfar_driver_version[];
 #define IEVENT_CRL		0x00020000
 #define IEVENT_XFUN		0x00010000
 #define IEVENT_RXB0		0x00008000
+#define IEVENT_MAG		0x00000800
 #define IEVENT_GRSC		0x00000100
 #define IEVENT_RXF0		0x00000080
 #define IEVENT_FIR		0x00000008
@@ -245,7 +247,8 @@ extern const char gfar_driver_version[];
 #define IEVENT_ERR_MASK         \
 (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
  IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR \
+ | IEVENT_MAG)
 
 #define IMASK_INIT_CLEAR	0x00000000
 #define IMASK_BABR              0x80000000
@@ -263,6 +266,7 @@ extern const char gfar_driver_version[];
 #define IMASK_CRL		0x00020000
 #define IMASK_XFUN		0x00010000
 #define IMASK_RXB0              0x00008000
+#define IMASK_MAG		0x00000800
 #define IMASK_GTSC              0x00000100
 #define IMASK_RXFEN0		0x00000080
 #define IMASK_FIR		0x00000008
@@ -726,10 +730,15 @@ struct gfar_private {
 	unsigned int fifo_starve;
 	unsigned int fifo_starve_off;
 
+	/* Bitfield update lock */
+	spinlock_t bflock;
+
 	unsigned char vlan_enable:1,
 		rx_csum_enable:1,
 		extended_hash:1,
-		bd_stash_en:1;
+		bd_stash_en:1,
+		wol_en:1, /* Wake-on-LAN enabled */
+		suspended:1;
 	unsigned short padding;
 
 	unsigned int interruptTransmit;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6007147..fb7d3cc 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -479,14 +479,13 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
 static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
 	int err = 0;
 
 	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
 		return -EOPNOTSUPP;
 
 	if (dev->flags & IFF_UP) {
-		unsigned long flags;
-
 		/* Halt TX and RX, and process the frames which
 		 * have already been received */
 		spin_lock_irqsave(&priv->txlock, flags);
@@ -502,7 +501,9 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
 		stop_gfar(dev);
 	}
 
+	spin_lock_irqsave(&priv->bflock, flags);
 	priv->rx_csum_enable = data;
+	spin_unlock_irqrestore(&priv->bflock, flags);
 
 	if (dev->flags & IFF_UP)
 		err = startup_gfar(dev);
@@ -564,6 +565,38 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
 	priv->msg_enable = data;
 }
 
+#ifdef CONFIG_PM
+static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+
+	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) {
+		wol->supported = WAKE_MAGIC;
+		wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0;
+	} else {
+		wol->supported = wol->wolopts = 0;
+	}
+}
+
+static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct gfar_private *priv = netdev_priv(dev);
+	unsigned long flags;
+
+	if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
+	    wol->wolopts != 0)
+		return -EINVAL;
+
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+
+	spin_lock_irqsave(&priv->bflock, flags);
+	priv->wol_en = wol->wolopts & WAKE_MAGIC ? 1 : 0;
+	spin_unlock_irqrestore(&priv->bflock, flags);
+
+	return 0;
+}
+#endif
 
 const struct ethtool_ops gfar_ethtool_ops = {
 	.get_settings = gfar_gsettings,
@@ -585,4 +618,8 @@ const struct ethtool_ops gfar_ethtool_ops = {
 	.set_tx_csum = gfar_set_tx_csum,
 	.get_msglevel = gfar_get_msglevel,
 	.set_msglevel = gfar_set_msglevel,
+#ifdef CONFIG_PM
+	.get_wol = gfar_get_wol,
+	.set_wol = gfar_set_wol,
+#endif
 };
-- 
1.5.3.7


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

^ permalink raw reply related

* [PATCH 7/7] linkstation: implement standby
From: Guennadi Liakhovetski @ 2008-04-28 15:40 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Stephen Rothwell, Paul Mackerras, Pavel Machek, Scott Wood,
	linux-pm, Johannes Berg
In-Reply-To: <Pine.LNX.4.64.0804281714000.7897@axis700.grange>

Implement suspend/resume for "mpc10x" compatible fsl host PCI controllers, 
use it for linkstation standby. This is version 3, updated to the current
powerpc git tree. Depends as before on TLF_SLEEPING and HID0_SLEEP patches
from Scott Wood.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 20f45a8..693da18 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -192,7 +192,7 @@ config ARCH_HIBERNATION_POSSIBLE
 
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
-	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx
+	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || MPC10X_BRIDGE
 
 config PPC_DCR_NATIVE
 	bool
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index eb5d74e..3bab51f 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -197,3 +197,54 @@ define_machine(linkstation){
 	.halt	 		= linkstation_halt,
 	.calibrate_decr 	= generic_calibrate_decr,
 };
+
+#ifdef CONFIG_PM_SLEEP
+
+#include <linux/suspend.h>
+#include <linux/serial_reg.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/mpc6xx.h>
+
+static int ls_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int ls_pm_enter(suspend_state_t state)
+{
+	u64 tb;
+
+	/* Get timebase */
+	tb = get_tb();
+
+	/* put CPU to sleep, re-enabling interrupts */
+	mpc6xx_enter_standby();
+
+	local_irq_disable();
+
+	set_tb(tb >> 32, tb & 0xfffffffful);
+
+	return 0;
+}
+
+static struct platform_suspend_ops ls_pm_ops = {
+	.valid		= ls_pm_valid,
+	.enter		= ls_pm_enter,
+};
+
+static int __init ls_pm_init(void)
+{
+	if (!machine_is(linkstation))
+		return -ENODEV;
+
+	suspend_set_ops(&ls_pm_ops);
+	return 0;
+}
+
+device_initcall(ls_pm_init);
+#endif
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 72fb35b..4df3230 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -6,3 +6,6 @@ config PPC4xx_PCI_EXPRESS
 	bool
 	depends on PCI && 4xx
 	default n
+
+config MPC10X_PM
+	def_bool FSL_SOC && PCI && PM_SLEEP
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 2cc5052..0b90cc8 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -48,3 +48,5 @@ endif
 ifeq ($(CONFIG_SUSPEND),y)
 obj-$(CONFIG_6xx)		+= 6xx-suspend.o
 endif
+
+obj-$(CONFIG_MPC10X_PM)		+= mpc10x_pm.o
diff -u /dev/null b/arch/powerpc/sysdev/mpc10x_pm.c
new file mode 100644
index 0000000..6bd773b
--- /dev/null	2008-04-28 10:35:13.531006534 +0200
+++ b/arch/powerpc/sysdev/mpc10x_pm.c	2008-04-25 21:18:19.000000000 +0200
@@ -0,0 +1,73 @@
+/*
+ * Power-management driver for MPC8241 host-PCI controller
+ *
+ * Copyright (C) 2007 G. Liakhovetski (g.liakhovetski@gmx.de)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of
+ * any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+
+#include <asm/pci-bridge.h>
+
+#define	MPC10X_LP_REF_EN	(1<<12)
+#define	MPC10X_PM		(1<<7)
+#define MPC10X_DOZE		(1<<5)
+#define	MPC10X_NAP		(1<<4)
+#define	MPC10X_SLEEP		(1<<3)
+
+static int __devinit mpc10x_pm_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *id)
+{
+	return 0;
+}
+
+static int mpc10x_pm_suspend_late(struct pci_dev *dev, pm_message_t state)
+{
+	u16 pmcr1;
+
+	pci_read_config_word(dev, 0x70, &pmcr1);
+	pmcr1 &= ~(MPC10X_DOZE | MPC10X_NAP);
+	pmcr1 |= MPC10X_PM | MPC10X_SLEEP | MPC10X_LP_REF_EN;
+	pci_write_config_word(dev, 0x70, pmcr1);
+
+	return 0;
+}
+
+static int mpc10x_pm_resume_early(struct pci_dev *dev)
+{
+	u16 pmcr1;
+
+	pci_read_config_word(dev, 0x70, &pmcr1);
+	pmcr1 &= ~(MPC10X_PM | MPC10X_DOZE | MPC10X_SLEEP | MPC10X_NAP | MPC10X_LP_REF_EN);
+	pci_write_config_word(dev, 0x70, pmcr1);
+
+	return 0;
+}
+
+static struct pci_device_id mpc10x_pm_pci_tbl[] = {
+	{ PCI_VENDOR_ID_MOTOROLA, PCI_DEVICE_ID_MOTOROLA_MPC8241,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, mpc10x_pm_pci_tbl);
+
+static struct pci_driver mpc10x_pm_driver = {
+	.name		= "mpc10x-pm",
+	.id_table	= mpc10x_pm_pci_tbl,
+	.resume_early	= mpc10x_pm_resume_early,
+	.suspend_late	= mpc10x_pm_suspend_late,
+	.probe		= mpc10x_pm_probe,
+};
+
+static int __init mpc10x_pm_init(void)
+{
+	return pci_register_driver(&mpc10x_pm_driver);
+}
+
+device_initcall(mpc10x_pm_init);
diff --git a/include/asm-powerpc/mpc6xx.h b/include/asm-powerpc/mpc6xx.h
index effc229..9bdf8b4 100644
--- a/include/asm-powerpc/mpc6xx.h
+++ b/include/asm-powerpc/mpc6xx.h
@@ -1,6 +1,6 @@
 #ifndef __ASM_POWERPC_MPC6xx_H
 #define __ASM_POWERPC_MPC6xx_H
 
-void mpc6xx_enter_standby(void);
+extern void mpc6xx_enter_standby(void);
 
 #endif
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70eb3c8..9eb84cc 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -800,6 +800,7 @@
 #define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
 #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
 #define PCI_DEVICE_ID_MOTOROLA_MPC107	0x0004
+#define PCI_DEVICE_ID_MOTOROLA_MPC8241	0x0006
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
 #define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
 #define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803

^ permalink raw reply related

* Re: [PATCH 1/2] i2c: Add support for device alias names
From: Jean Delvare @ 2008-04-28 15:40 UTC (permalink / raw)
  To: Kay Sievers; +Cc: linuxppc-dev list, Paul Mundt, Scott Wood, Jon, Linux I2C
In-Reply-To: <1209395245.3666.9.camel@linux.site>

Hi Kay,

On Mon, 28 Apr 2008 17:07:25 +0200, Kay Sievers wrote:
> On Mon, 2008-04-28 at 11:39 +0200, Jean Delvare wrote:
> > One thing I am still not happy with is that the aliases created have a
> > trailing "*":
> >=20
> > $ /sbin/modinfo lm90
> > filename:       /lib/modules/2.6.25-git11/kernel/drivers/hwmon/lm90.ko
> > author:         Jean Delvare <khali@linux-fr.org>
> > description:    LM90/ADM1032 driver
> > license:        GPL
> > vermagic:       2.6.25-git11 mod_unload
> > depends:        hwmon
> > alias:          i2c:lm90*
> > alias:          i2c:adm1032*
> > alias:          i2c:lm99*
> > alias:          i2c:lm86*
> > alias:          i2c:max6657*
> > alias:          i2c:adt7461*
> > alias:          i2c:max6680*
> > $
> >=20
> > This would cause trouble if one I2C chip name matches the beginning of
> > another I2C chip name and both chips are supported by different
> > drivers. This has yet to be seen, but still, I'd like to see this
> > problem fixed quickly.
>=20
> =EF=BB=BFRight, the trailing "*" is not nice.
>=20
> We should terminate the string, so the trailing "*" will not match
> longer strings. The usual thing is to add a ":" to the end, which would
> then show up as
>   alias: i2c:max6680:*
>=20
> See DMI and ACPI:
>   alias dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:* apanel
>   alias acpi*:ASIM0000:* atlas_btns

I didn't know about these cases, thanks for the hint.

>=20
> If i2c device modaliases could ever contain multiple strings, it should
> be:
>   alias: i2c*:max6680:*
> =EF=BB=BFto match the module, regardless of the order of the strings in t=
he
> modalias:

Why would i2c device modaliases ever contain multiple strings? A device
can't have multiple names, can it?

Adding a ":" at the end of the i2c device names solves the problem I
was mentioning, sure, but why don't we simply remove the trailing "*",
instead of trying to work around it? A trailing "*" simply makes no
sense for aliases which are simple device names. This is not only i2c
devices, but also platform devices, acpi, dmi, pnp... Looking at the
various device types handled by file2alias.c, it seems that most of
them don't need the trailing "*", and many of them have the problem I
was mentioning.

Can't we just stop handle_moddevtable() from adding a tailing "*"
automatically, and just let the device types which need it, add it on
their own?

Thanks,
--=20
Jean Delvare

^ permalink raw reply

* suggestions on handling additional exception levels on ppc32
From: Kumar Gala @ 2008-04-28 15:40 UTC (permalink / raw)
  To: linuxppc-dev@ozlabs.org list

I'm looking at fixing an issue parts that have multiple exception  
levels (e300, 40x, booke).

One of the issues is the transfer_to_handler patch in entry_32.S  
doesn't use the proper save/restore registers to transfer to C code.

The following bit of code is what I'm having issues with:

         .globl transfer_to_handler_cont
transfer_to_handler_cont:
3:
         mflr    r9
         lwz     r11,0(r9)               /* virtual address of handler  
*/
         lwz     r9,4(r9)                /* where to go when done */
         mtspr   SPRN_SRR0,r11
         mtspr   SPRN_SRR1,r10
         mtlr    r9
         SYNC
         RFI                             /* jump to handler, enable  
MMU */

A few possibilities:
* introduce an additional function pointer as part of  
EXC_XFER_TEMPLATE() to specifies the type of handler (normal, crit,  
dbg, mcheck)
* use the traps field low order bits to determine normal, crit, dbg,  
mcheck at run time.
* duplicate the code paths for each exception level

suggestions?

- k

^ permalink raw reply

* Re: [PATCH] Add fast little-endian switch system call
From: Michael Kerrisk @ 2008-04-28 15:42 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-arch, linuxppc-dev, Paul Mackerras, mtk.manpages
In-Reply-To: <20080428144332.GA17109@lst.de>

On Mon, Apr 28, 2008 at 4:43 PM, Christoph Hellwig <hch@lst.de> wrote:
> Please see Michael Kerrisk on userspace ABI updates.  A nice little
> manpage for this gimmick would be helpful, and maybe help other
> platforms that want one aswell to implement the same API.

Thanks Chrsitoph.  I'm not on any of these lists at the moment.

Paul -- is this syscall defintely going in?  Could you write a short
description for userland programmers?  I'll do the grotty *roff stuff.

> On Mon, Apr 28, 2008 at 01:52:31PM +1000, Paul Mackerras wrote:
> > This adds a system call on 64-bit platforms for switching between
> > little-endian and big-endian modes that is much faster than doing a
> > prctl call.  This system call is handled as a special case right at
> > the start of the system call entry code, and because it is a special
> > case, it uses a system call number which is out of the range of
> > normal system calls, namely 0x1ebe.
> >
> > Measurements with lmbench on a 4.2GHz POWER6 showed no measurable
> > change in the speed of normal system calls with this patch.
> >
> > Switching endianness with this new system call takes around 60ns on a
> > 4.2GHz POWER6, compared with around 300ns to switch endian mode with a
> > prctl.  This can provide a significant performance advantage for
> > emulators for little-endian architectures that want to switch between
> > big-endian and little-endian mode frequently, e.g. because they are
> > generating instructions sequences on the fly and they want to run
> > those sequences in little-endian mode.
> >
> > Signed-off-by: Paul Mackerras <paulus@samba.org>
> > ---
> >
> > diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
> > index 215973a..2eb49a7 100644
> > --- a/arch/powerpc/kernel/head_64.S
> > +++ b/arch/powerpc/kernel/head_64.S
> > @@ -239,6 +239,10 @@ instruction_access_slb_pSeries:
> >       .globl  system_call_pSeries
> >  system_call_pSeries:
> >       HMT_MEDIUM
> > +BEGIN_FTR_SECTION
> > +     cmpdi   r0,0x1ebe
> > +     beq-    1f
> > +END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
>
> Am I missing something here or does this add a branch for every normal
> syscall?
>
> >       mr      r9,r13
> >       mfmsr   r10
> >       mfspr   r13,SPRN_SPRG3
> > @@ -253,6 +257,13 @@ system_call_pSeries:
> >       rfid
> >       b       .       /* prevent speculative execution */
> >
> > +/* Fast LE/BE switch system call */
> > +1:   mfspr   r12,SPRN_SRR1
> > +     xori    r12,r12,MSR_LE
> > +     mtspr   SPRN_SRR1,r12
> > +     rfid            /* return to userspace */
> > +     b       .
> > +
> >       STD_EXCEPTION_PSERIES(0xd00, single_step)
> >       STD_EXCEPTION_PSERIES(0xe00, trap_0e)
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
> ---end quoted text---
>



-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Found a bug? http://www.kernel.org/doc/man-pages/reporting_bugs.html

^ 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