LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Heiko Schocher @ 2011-05-03  7:24 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <BANLkTimacM29RHExZounuziF+7jARQxdTg@mail.gmail.com>

Hello Grant,

Grant Likely wrote:
> On Mon, May 2, 2011 at 11:17 PM, Heiko Schocher <hs@denx.de> wrote:
>> Hello Grant,
>>
>> Grant Likely wrote:
>>> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>>>> cc: Wolfram Sang <w.sang@pengutronix.de>
>>>> cc: Grant Likely <grant.likely@secretlab.ca>
>>>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>>> cc: linux-fbdev@vger.kernel.org
>>>> cc: devicetree-discuss@ozlabs.org
>>>> cc: Ben Dooks <ben@simtec.co.uk>
>>>> cc: Vincent Sanders <vince@simtec.co.uk>
>>>> cc: Samuel Ortiz <sameo@linux.intel.com>
>>>> cc: linux-kernel@vger.kernel.org
>>>> cc: Randy Dunlap <rdunlap@xenotime.net>
>>>> cc: Wolfgang Denk <wd@denx.de>
>>>> cc: Paul Mundt <lethal@linux-sh.org>
>>>>
>>>> changes since v5:
>>>> - repost complete patchseries, as Paul Mundt suggested
>>>> - rebased against current head
>>>> - add Acked-by from Samuel Ortiz (MFD parts)
>>>>   http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>>>   http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.html
>>>>
>>>>   and Benjamin Herrenschmidt (DTS parts)
>>>>   http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279.html
>>>> - removed patch
>>>>   "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board."
>>>>   therefore added
>>>>   "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board."
>>> Refresh my memory, why was the mpc5200_defconfig updated dropped?
>> Because it is a board based on the tqm5200 board port ... no other
>> reason.
> 
> Please send a patch to also update the mpc5200_defconfig.

Ok. Done, just one more question:

Why you didn;t pick up the patches:

- powerpc, 5200: add support for charon board
  (Got an Acked-by from Wolfram Sang)
- powerpc, video: add SM501 support for charon board.

Are there any issues with them, I should fix?

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Anton Blanchard @ 2011-05-03  6:55 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <1304405237.2513.304.camel@pasglop>


Hi Ben,

> My only comment (sorry Anton :-) would have been that we could lazily
> allocate the spinlock on the first use_cop() ... or do we have that
> potentially called in the wrong context ?

I worry what might happen in a threaded app. It would be a strange
thing to do, but the program may call use_cop from two threads at the
same time. In that case you could corrupt the PID/ACOP values
and leak a spinlock of memory I think.

Anton

^ permalink raw reply

* Re: [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Benjamin Herrenschmidt @ 2011-05-03  6:47 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: tsenglin, linuxppc-dev
In-Reply-To: <20110503164304.7690a1b7@kryten>

On Tue, 2011-05-03 at 16:43 +1000, Anton Blanchard wrote:
> From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
> 
> Icswx is a PowerPC instruction to send data to a co-processor. On Book-S
> processors the LPAR_ID and process ID (PID) of the owning process are
> registered in the window context of the co-processor at initialization
> time. When the icswx instruction is executed the L2 generates a cop-reg
> transaction on PowerBus. The transaction has no address and the
> processor does not perform an MMU access to authenticate the transaction.
> The co-processor compares the LPAR_ID and the PID included in the
> transaction and the LPAR_ID and PID held in the window context to
> determine if the process is authorized to generate the transaction.
> 
> The OS needs to assign a 16-bit PID for the process. This cop-PID needs
> to be updated during context switch. The cop-PID needs to be destroyed
> when the context is destroyed.

> Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com>
> Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
> Signed-off-by: Anton Blanchard <anton@samba.org>
> ---
> 
> Changes:
> 
> - Go back to dynamically allocating the spinlock to avoid the mmu_context.h
>   and spinlock_types.h include mess.

My only comment (sorry Anton :-) would have been that we could lazily
allocate the spinlock on the first use_cop() ... or do we have that
potentially called in the wrong context ?

Cheers,
Ben.

> Index: linux-powerpc/arch/powerpc/include/asm/cputable.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:21.779140935 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:26.059220272 +1000
> @@ -197,6 +197,7 @@ extern const char *powerpc_base_platform
>  #define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
>  #define CPU_FTR_POPCNTB			LONG_ASM_CONST(0x0400000000000000)
>  #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
> +#define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
>  
>  #ifndef __ASSEMBLY__
>  
> @@ -418,7 +419,8 @@ extern const char *powerpc_base_platform
>  	    CPU_FTR_COHERENT_ICACHE | \
>  	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
>  	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
> -	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
> +	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
> +	    CPU_FTR_ICSWX)
>  #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
>  	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
>  	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
> Index: linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:21.789141120 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:26.059220272 +1000
> @@ -408,6 +408,7 @@ static inline void subpage_prot_init_new
>  #endif /* CONFIG_PPC_SUBPAGE_PROT */
>  
>  typedef unsigned long mm_context_id_t;
> +struct spinlock;
>  
>  typedef struct {
>  	mm_context_id_t id;
> @@ -423,6 +424,11 @@ typedef struct {
>  #ifdef CONFIG_PPC_SUBPAGE_PROT
>  	struct subpage_prot_table spt;
>  #endif /* CONFIG_PPC_SUBPAGE_PROT */
> +#ifdef CONFIG_PPC_ICSWX
> +	struct spinlock *cop_lockp; /* guard acop and cop_pid */
> +	unsigned long acop;	/* mask of enabled coprocessor types */
> +	unsigned int cop_pid;	/* pid value used with coprocessors */
> +#endif /* CONFIG_PPC_ICSWX */
>  } mm_context_t;
>  
> 
> Index: linux-powerpc/arch/powerpc/include/asm/mmu_context.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:21.779140935 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:26.059220272 +1000
> @@ -32,6 +32,10 @@ extern void __destroy_context(unsigned l
>  extern void mmu_context_init(void);
>  #endif
>  
> +extern void switch_cop(struct mm_struct *next);
> +extern int use_cop(unsigned long acop, struct mm_struct *mm);
> +extern void drop_cop(unsigned long acop, struct mm_struct *mm);
> +
>  /*
>   * switch_mm is the entry point called from the architecture independent
>   * code in kernel/sched.c
> @@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_s
>  	if (prev == next)
>  		return;
>  
> +#ifdef CONFIG_PPC_ICSWX
> +	/* Switch coprocessor context only if prev or next uses a coprocessor */
> +	if (prev->context.acop || next->context.acop)
> +		switch_cop(next);
> +#endif /* CONFIG_PPC_ICSWX */
> +
>  	/* We must stop all altivec streams before changing the HW
>  	 * context
>  	 */
> Index: linux-powerpc/arch/powerpc/include/asm/reg.h
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:21.799141306 +1000
> +++ linux-powerpc/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:26.059220272 +1000
> @@ -188,6 +188,7 @@
>  
>  #define SPRN_CTR	0x009	/* Count Register */
>  #define SPRN_DSCR	0x11
> +#define SPRN_ACOP	0x1F	/* Available Coprocessor Register */
>  #define SPRN_CTRLF	0x088
>  #define SPRN_CTRLT	0x098
>  #define   CTRL_CT	0xc0000000	/* current thread */
> Index: linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:21.759140565 +1000
> +++ linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:26.059220272 +1000
> @@ -20,9 +20,205 @@
>  #include <linux/idr.h>
>  #include <linux/module.h>
>  #include <linux/gfp.h>
> +#include <linux/slab.h>
>  
>  #include <asm/mmu_context.h>
>  
> +#ifdef CONFIG_PPC_ICSWX
> +/*
> + * The processor and its L2 cache cause the icswx instruction to
> + * generate a COP_REQ transaction on PowerBus. The transaction has
> + * no address, and the processor does not perform an MMU access
> + * to authenticate the transaction. The command portion of the
> + * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> + * the coprocessor Process ID (PID), which the coprocessor compares
> + * to the authorized LPID and PID held in the coprocessor, to determine
> + * if the process is authorized to generate the transaction.
> + * The data of the COP_REQ transaction is 128-byte or less and is
> + * placed in cacheable memory on a 128-byte cache line boundary.
> + *
> + * The task to use a coprocessor should use use_cop() to allocate
> + * a coprocessor PID before executing icswx instruction. use_cop()
> + * also enables the coprocessor context switching. Drop_cop() is
> + * used to free the coprocessor PID.
> + *
> + * Example:
> + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> + * Each HFI have multiple windows. Each HFI window serves as a
> + * network device sending to and receiving from HFI network.
> + * HFI immediate send function uses icswx instruction. The immediate
> + * send function allows small (single cache-line) packets be sent
> + * without using the regular HFI send FIFO and doorbell, which are
> + * much slower than immediate send.
> + *
> + * For each task intending to use HFI immediate send, the HFI driver
> + * calls use_cop() to obtain a coprocessor PID for the task.
> + * The HFI driver then allocate a free HFI window and save the
> + * coprocessor PID to the HFI window to allow the task to use the
> + * HFI window.
> + *
> + * The HFI driver repeatedly creates immediate send packets and
> + * issues icswx instruction to send data through the HFI window.
> + * The HFI compares the coprocessor PID in the CPU PID register
> + * to the PID held in the HFI window to determine if the transaction
> + * is allowed.
> + *
> + * When the task to release the HFI window, the HFI driver calls
> + * drop_cop() to release the coprocessor PID.
> + */
> +
> +#define COP_PID_NONE 0
> +#define COP_PID_MIN (COP_PID_NONE + 1)
> +#define COP_PID_MAX (0xFFFF)
> +
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +void switch_cop(struct mm_struct *next)
> +{
> +	mtspr(SPRN_PID, next->context.cop_pid);
> +	mtspr(SPRN_ACOP, next->context.acop);
> +}
> +
> +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> +		       spinlock_t *lock)
> +{
> +	int index;
> +	int err;
> +
> +again:
> +	if (!ida_pre_get(ida, GFP_KERNEL))
> +		return -ENOMEM;
> +
> +	spin_lock(lock);
> +	err = ida_get_new_above(ida, min_id, &index);
> +	spin_unlock(lock);
> +
> +	if (err == -EAGAIN)
> +		goto again;
> +	else if (err)
> +		return err;
> +
> +	if (index > max_id) {
> +		spin_lock(lock);
> +		ida_remove(ida, index);
> +		spin_unlock(lock);
> +		return -ENOMEM;
> +	}
> +
> +	return index;
> +}
> +
> +static void sync_cop(void *arg)
> +{
> +	struct mm_struct *mm = arg;
> +
> +	if (mm == current->active_mm)
> +		switch_cop(current->active_mm);
> +}
> +
> +/**
> + * Start using a coprocessor.
> + * @acop: mask of coprocessor to be used.
> + * @mm: The mm the coprocessor to associate with. Most likely current mm.
> + *
> + * Return a positive PID if successful. Negative errno otherwise.
> + * The returned PID will be fed to the coprocessor to determine if an
> + * icswx transaction is authenticated.
> + */
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int ret;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return -ENODEV;
> +
> +	if (!mm || !acop)
> +		return -EINVAL;
> +
> +	/* We need to make sure mm_users doesn't change */
> +	down_read(&mm->mmap_sem);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	if (mm->context.cop_pid == COP_PID_NONE) {
> +		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> +				  &mmu_context_acop_lock);
> +		if (ret < 0)
> +			goto out;
> +
> +		mm->context.cop_pid = ret;
> +	}
> +	mm->context.acop |= acop;
> +
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other threads
> +	 * running. We need to send an IPI to force them to pick up any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +	ret = mm->context.cop_pid;
> +
> +out:
> +	spin_unlock(mm->context.cop_lockp);
> +	up_read(&mm->mmap_sem);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(use_cop);
> +
> +/**
> + * Stop using a coprocessor.
> + * @acop: mask of coprocessor to be stopped.
> + * @mm: The mm the coprocessor associated with.
> + */
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +	int free_pid = COP_PID_NONE;
> +
> +	if (!cpu_has_feature(CPU_FTR_ICSWX))
> +		return;
> +
> +	if (WARN_ON_ONCE(!mm))
> +		return;
> +
> +	/* We need to make sure mm_users doesn't change */
> +	down_read(&mm->mmap_sem);
> +	spin_lock(mm->context.cop_lockp);
> +
> +	mm->context.acop &= ~acop;
> +
> +	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
> +		free_pid = mm->context.cop_pid;
> +		mm->context.cop_pid = COP_PID_NONE;
> +	}
> +
> +	sync_cop(mm);
> +
> +	/*
> +	 * If this is a threaded process then there might be other threads
> +	 * running. We need to send an IPI to force them to pick up any
> +	 * change in PID and ACOP.
> +	 */
> +	if (atomic_read(&mm->mm_users) > 1)
> +		smp_call_function(sync_cop, mm, 1);
> +
> +	if (free_pid != COP_PID_NONE) {
> +		spin_lock(&mmu_context_acop_lock);
> +		ida_remove(&cop_ida, free_pid);
> +		spin_unlock(&mmu_context_acop_lock);
> +	}
> +
> +	spin_unlock(mm->context.cop_lockp);
> +	up_read(&mm->mmap_sem);
> +}
> +EXPORT_SYMBOL_GPL(drop_cop);
> +
> +#endif /* CONFIG_PPC_ICSWX */
> +
>  static DEFINE_SPINLOCK(mmu_context_lock);
>  static DEFINE_IDA(mmu_context_ida);
>  
> @@ -78,6 +274,16 @@ int init_new_context(struct task_struct
>  		slice_set_user_psize(mm, mmu_virtual_psize);
>  	subpage_prot_init_new_context(mm);
>  	mm->context.id = index;
> +#ifdef CONFIG_PPC_ICSWX
> +	mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
> +	if (!mm->context.cop_lockp) {
> +		__destroy_context(index);
> +		subpage_prot_free(mm);
> +		mm->context.id = NO_CONTEXT;
> +		return -ENOMEM;
> +	}
> +	spin_lock_init(mm->context.cop_lockp);
> +#endif /* CONFIG_PPC_ICSWX */
>  
>  	return 0;
>  }
> @@ -92,6 +298,11 @@ EXPORT_SYMBOL_GPL(__destroy_context);
>  
>  void destroy_context(struct mm_struct *mm)
>  {
> +#ifdef CONFIG_PPC_ICSWX
> +	drop_cop(mm->context.acop, mm);
> +	kfree(mm->context.cop_lockp);
> +	mm->context.cop_lockp = NULL;
> +#endif /* CONFIG_PPC_ICSWX */
>  	__destroy_context(mm->context.id);
>  	subpage_prot_free(mm);
>  	mm->context.id = MMU_NO_CONTEXT;
> Index: linux-powerpc/arch/powerpc/platforms/Kconfig.cputype
> ===================================================================
> --- linux-powerpc.orig/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:21.809141492 +1000
> +++ linux-powerpc/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:26.059220272 +1000
> @@ -230,6 +230,24 @@ config VSX
>  
>  	  If in doubt, say Y here.
>  
> +config PPC_ICSWX
> +	bool "Support for PowerPC icswx coprocessor instruction"
> +	depends on POWER4
> +	default n
> +	---help---
> +
> +	  This option enables kernel support for the PowerPC Initiate
> +	  Coprocessor Store Word (icswx) coprocessor instruction on POWER7
> +	  or newer processors.
> +
> +	  This option is only useful if you have a processor that supports
> +	  the icswx coprocessor instruction. It does not have any effect
> +	  on processors without the icswx coprocessor instruction.
> +
> +	  This option slightly increases kernel memory usage.
> +
> +	  If in doubt, say N here.
> +
>  config SPE
>  	bool "SPE Support"
>  	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply

* [PATCH] powerpc: Add Initiate Coprocessor Store Word (icswx) support
From: Anton Blanchard @ 2011-05-03  6:43 UTC (permalink / raw)
  To: benh, tsenglin; +Cc: linuxppc-dev

From: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>

Icswx is a PowerPC instruction to send data to a co-processor. On Book-S
processors the LPAR_ID and process ID (PID) of the owning process are
registered in the window context of the co-processor at initialization
time. When the icswx instruction is executed the L2 generates a cop-reg
transaction on PowerBus. The transaction has no address and the
processor does not perform an MMU access to authenticate the transaction.
The co-processor compares the LPAR_ID and the PID included in the
transaction and the LPAR_ID and PID held in the window context to
determine if the process is authorized to generate the transaction.

The OS needs to assign a 16-bit PID for the process. This cop-PID needs
to be updated during context switch. The cop-PID needs to be destroyed
when the context is destroyed.

Signed-off-by: Sonny Rao <sonnyrao@linux.vnet.ibm.com>
Signed-off-by: Tseng-Hui (Frank) Lin <thlin@linux.vnet.ibm.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
---

Changes:

- Go back to dynamically allocating the spinlock to avoid the mmu_context.h
  and spinlock_types.h include mess.

Index: linux-powerpc/arch/powerpc/include/asm/cputable.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:21.779140935 +1000
+++ linux-powerpc/arch/powerpc/include/asm/cputable.h	2011-05-03 16:39:26.059220272 +1000
@@ -197,6 +197,7 @@ extern const char *powerpc_base_platform
 #define CPU_FTR_STCX_CHECKS_ADDRESS	LONG_ASM_CONST(0x0200000000000000)
 #define CPU_FTR_POPCNTB			LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -418,7 +419,8 @@ extern const char *powerpc_base_platform
 	    CPU_FTR_COHERENT_ICACHE | \
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
-	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+	    CPU_FTR_ICSWX)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
Index: linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:21.789141120 +1000
+++ linux-powerpc/arch/powerpc/include/asm/mmu-hash64.h	2011-05-03 16:39:26.059220272 +1000
@@ -408,6 +408,7 @@ static inline void subpage_prot_init_new
 #endif /* CONFIG_PPC_SUBPAGE_PROT */
 
 typedef unsigned long mm_context_id_t;
+struct spinlock;
 
 typedef struct {
 	mm_context_id_t id;
@@ -423,6 +424,11 @@ typedef struct {
 #ifdef CONFIG_PPC_SUBPAGE_PROT
 	struct subpage_prot_table spt;
 #endif /* CONFIG_PPC_SUBPAGE_PROT */
+#ifdef CONFIG_PPC_ICSWX
+	struct spinlock *cop_lockp; /* guard acop and cop_pid */
+	unsigned long acop;	/* mask of enabled coprocessor types */
+	unsigned int cop_pid;	/* pid value used with coprocessors */
+#endif /* CONFIG_PPC_ICSWX */
 } mm_context_t;
 
 
Index: linux-powerpc/arch/powerpc/include/asm/mmu_context.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:21.779140935 +1000
+++ linux-powerpc/arch/powerpc/include/asm/mmu_context.h	2011-05-03 16:39:26.059220272 +1000
@@ -32,6 +32,10 @@ extern void __destroy_context(unsigned l
 extern void mmu_context_init(void);
 #endif
 
+extern void switch_cop(struct mm_struct *next);
+extern int use_cop(unsigned long acop, struct mm_struct *mm);
+extern void drop_cop(unsigned long acop, struct mm_struct *mm);
+
 /*
  * switch_mm is the entry point called from the architecture independent
  * code in kernel/sched.c
@@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_s
 	if (prev == next)
 		return;
 
+#ifdef CONFIG_PPC_ICSWX
+	/* Switch coprocessor context only if prev or next uses a coprocessor */
+	if (prev->context.acop || next->context.acop)
+		switch_cop(next);
+#endif /* CONFIG_PPC_ICSWX */
+
 	/* We must stop all altivec streams before changing the HW
 	 * context
 	 */
Index: linux-powerpc/arch/powerpc/include/asm/reg.h
===================================================================
--- linux-powerpc.orig/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:21.799141306 +1000
+++ linux-powerpc/arch/powerpc/include/asm/reg.h	2011-05-03 16:39:26.059220272 +1000
@@ -188,6 +188,7 @@
 
 #define SPRN_CTR	0x009	/* Count Register */
 #define SPRN_DSCR	0x11
+#define SPRN_ACOP	0x1F	/* Available Coprocessor Register */
 #define SPRN_CTRLF	0x088
 #define SPRN_CTRLT	0x098
 #define   CTRL_CT	0xc0000000	/* current thread */
Index: linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c
===================================================================
--- linux-powerpc.orig/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:21.759140565 +1000
+++ linux-powerpc/arch/powerpc/mm/mmu_context_hash64.c	2011-05-03 16:39:26.059220272 +1000
@@ -20,9 +20,205 @@
 #include <linux/idr.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 
 #include <asm/mmu_context.h>
 
+#ifdef CONFIG_PPC_ICSWX
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has
+ * no address, and the processor does not perform an MMU access
+ * to authenticate the transaction. The command portion of the
+ * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
+ * the coprocessor Process ID (PID), which the coprocessor compares
+ * to the authorized LPID and PID held in the coprocessor, to determine
+ * if the process is authorized to generate the transaction.
+ * The data of the COP_REQ transaction is 128-byte or less and is
+ * placed in cacheable memory on a 128-byte cache line boundary.
+ *
+ * The task to use a coprocessor should use use_cop() to allocate
+ * a coprocessor PID before executing icswx instruction. use_cop()
+ * also enables the coprocessor context switching. Drop_cop() is
+ * used to free the coprocessor PID.
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+#define COP_PID_NONE 0
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+void switch_cop(struct mm_struct *next)
+{
+	mtspr(SPRN_PID, next->context.cop_pid);
+	mtspr(SPRN_ACOP, next->context.acop);
+}
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+		       spinlock_t *lock)
+{
+	int index;
+	int err;
+
+again:
+	if (!ida_pre_get(ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(lock);
+	err = ida_get_new_above(ida, min_id, &index);
+	spin_unlock(lock);
+
+	if (err == -EAGAIN)
+		goto again;
+	else if (err)
+		return err;
+
+	if (index > max_id) {
+		spin_lock(lock);
+		ida_remove(ida, index);
+		spin_unlock(lock);
+		return -ENOMEM;
+	}
+
+	return index;
+}
+
+static void sync_cop(void *arg)
+{
+	struct mm_struct *mm = arg;
+
+	if (mm == current->active_mm)
+		switch_cop(current->active_mm);
+}
+
+/**
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int ret;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return -ENODEV;
+
+	if (!mm || !acop)
+		return -EINVAL;
+
+	/* We need to make sure mm_users doesn't change */
+	down_read(&mm->mmap_sem);
+	spin_lock(mm->context.cop_lockp);
+
+	if (mm->context.cop_pid == COP_PID_NONE) {
+		ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+				  &mmu_context_acop_lock);
+		if (ret < 0)
+			goto out;
+
+		mm->context.cop_pid = ret;
+	}
+	mm->context.acop |= acop;
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	ret = mm->context.cop_pid;
+
+out:
+	spin_unlock(mm->context.cop_lockp);
+	up_read(&mm->mmap_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/**
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+	int free_pid = COP_PID_NONE;
+
+	if (!cpu_has_feature(CPU_FTR_ICSWX))
+		return;
+
+	if (WARN_ON_ONCE(!mm))
+		return;
+
+	/* We need to make sure mm_users doesn't change */
+	down_read(&mm->mmap_sem);
+	spin_lock(mm->context.cop_lockp);
+
+	mm->context.acop &= ~acop;
+
+	if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+		free_pid = mm->context.cop_pid;
+		mm->context.cop_pid = COP_PID_NONE;
+	}
+
+	sync_cop(mm);
+
+	/*
+	 * If this is a threaded process then there might be other threads
+	 * running. We need to send an IPI to force them to pick up any
+	 * change in PID and ACOP.
+	 */
+	if (atomic_read(&mm->mm_users) > 1)
+		smp_call_function(sync_cop, mm, 1);
+
+	if (free_pid != COP_PID_NONE) {
+		spin_lock(&mmu_context_acop_lock);
+		ida_remove(&cop_ida, free_pid);
+		spin_unlock(&mmu_context_acop_lock);
+	}
+
+	spin_unlock(mm->context.cop_lockp);
+	up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
+
+#endif /* CONFIG_PPC_ICSWX */
+
 static DEFINE_SPINLOCK(mmu_context_lock);
 static DEFINE_IDA(mmu_context_ida);
 
@@ -78,6 +274,16 @@ int init_new_context(struct task_struct
 		slice_set_user_psize(mm, mmu_virtual_psize);
 	subpage_prot_init_new_context(mm);
 	mm->context.id = index;
+#ifdef CONFIG_PPC_ICSWX
+	mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+	if (!mm->context.cop_lockp) {
+		__destroy_context(index);
+		subpage_prot_free(mm);
+		mm->context.id = NO_CONTEXT;
+		return -ENOMEM;
+	}
+	spin_lock_init(mm->context.cop_lockp);
+#endif /* CONFIG_PPC_ICSWX */
 
 	return 0;
 }
@@ -92,6 +298,11 @@ EXPORT_SYMBOL_GPL(__destroy_context);
 
 void destroy_context(struct mm_struct *mm)
 {
+#ifdef CONFIG_PPC_ICSWX
+	drop_cop(mm->context.acop, mm);
+	kfree(mm->context.cop_lockp);
+	mm->context.cop_lockp = NULL;
+#endif /* CONFIG_PPC_ICSWX */
 	__destroy_context(mm->context.id);
 	subpage_prot_free(mm);
 	mm->context.id = MMU_NO_CONTEXT;
Index: linux-powerpc/arch/powerpc/platforms/Kconfig.cputype
===================================================================
--- linux-powerpc.orig/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:21.809141492 +1000
+++ linux-powerpc/arch/powerpc/platforms/Kconfig.cputype	2011-05-03 16:39:26.059220272 +1000
@@ -230,6 +230,24 @@ config VSX
 
 	  If in doubt, say Y here.
 
+config PPC_ICSWX
+	bool "Support for PowerPC icswx coprocessor instruction"
+	depends on POWER4
+	default n
+	---help---
+
+	  This option enables kernel support for the PowerPC Initiate
+	  Coprocessor Store Word (icswx) coprocessor instruction on POWER7
+	  or newer processors.
+
+	  This option is only useful if you have a processor that supports
+	  the icswx coprocessor instruction. It does not have any effect
+	  on processors without the icswx coprocessor instruction.
+
+	  This option slightly increases kernel memory usage.
+
+	  If in doubt, say N here.
+
 config SPE
 	bool "SPE Support"
 	depends on E200 || (E500 && !PPC_E500MC)

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-03  5:43 UTC (permalink / raw)
  To: hs
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <4DBF922F.8040703@denx.de>

On Mon, May 2, 2011 at 11:27 PM, Heiko Schocher <hs@denx.de> wrote:
> Hello Grant,
>
> Grant Likely wrote:
>> On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca>=
 wrote:
>>> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>>>> - add commandline options:
>>>> =A0 sm501fb.mode:
>>>> =A0 =A0 Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>>>> =A0 sm501fb.bpp:
>>>> =A0 =A0 Specify bit-per-pixel if not specified mode
>>>>
>>>> - Add support for encoding display mode information
>>>> =A0 in the device tree using verbatim EDID block.
>>>>
>>>> =A0 If the "edid" entry in the "smi,sm501" node is present,
>>>> =A0 the driver will build mode database using EDID data
>>>> =A0 and allow setting the display modes from this database.
>>>>
>>>> Signed-off-by: Heiko Schocher <hs@denx.de>
>>> Merged, thanks.
>>
>> This patch causes the following build warning:
>
> Hups ... when I posted the patch, it compiled clean ...
>
>> =A0 MODPOST vmlinux.o
>> WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
>> the function sm501fb_init_fb() to the variable
>> .devinit.data:sm501_default_mode
>> The function sm501fb_init_fb() references
>> the variable __devinitdata sm501_default_mode.
>> This is often because sm501fb_init_fb lacks a __devinitdata
>> annotation or the annotation of sm501_default_mode is wrong.
>>
>> WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
>> the function sm501fb_init_fb() to the variable
>> .devinit.data:sm501_default_mode
>> The function sm501fb_init_fb() references
>> the variable __devinitdata sm501_default_mode.
>> This is often because sm501fb_init_fb lacks a __devinitdata
>> annotation or the annotation of sm501_default_mode is wrong.
>>
>> I've dropped the __devinitdata declaration in what I committed; can
>> you investigate and post a fixup patch?
>
> Of course, I look ASAP at it, thanks!
> (Dummy question: where can I find your tree?)

git://git.secretlab.ca/git/linux-2.6 powerpc/next

g.

>
> bye,
> Heiko
> --
> DENX Software Engineering GmbH, =A0 =A0 MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>



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

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Grant Likely @ 2011-05-03  5:42 UTC (permalink / raw)
  To: hs
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <4DBF8FF6.8030100@denx.de>

On Mon, May 2, 2011 at 11:17 PM, Heiko Schocher <hs@denx.de> wrote:
> Hello Grant,
>
> Grant Likely wrote:
>> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>>> cc: Wolfram Sang <w.sang@pengutronix.de>
>>> cc: Grant Likely <grant.likely@secretlab.ca>
>>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>>> cc: linux-fbdev@vger.kernel.org
>>> cc: devicetree-discuss@ozlabs.org
>>> cc: Ben Dooks <ben@simtec.co.uk>
>>> cc: Vincent Sanders <vince@simtec.co.uk>
>>> cc: Samuel Ortiz <sameo@linux.intel.com>
>>> cc: linux-kernel@vger.kernel.org
>>> cc: Randy Dunlap <rdunlap@xenotime.net>
>>> cc: Wolfgang Denk <wd@denx.de>
>>> cc: Paul Mundt <lethal@linux-sh.org>
>>>
>>> changes since v5:
>>> - repost complete patchseries, as Paul Mundt suggested
>>> - rebased against current head
>>> - add Acked-by from Samuel Ortiz (MFD parts)
>>> =A0 http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>> =A0 http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.ht=
ml
>>>
>>> =A0 and Benjamin Herrenschmidt (DTS parts)
>>> =A0 http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279=
.html
>>> - removed patch
>>> =A0 "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board=
."
>>> =A0 therefore added
>>> =A0 "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board=
."
>>
>> Refresh my memory, why was the mpc5200_defconfig updated dropped?
>
> Because it is a board based on the tqm5200 board port ... no other
> reason.

Please send a patch to also update the mpc5200_defconfig.

g.

^ permalink raw reply

* Re: Login prompt on a video console instead of serial port?
From: Benjamin Herrenschmidt @ 2011-05-03  5:41 UTC (permalink / raw)
  To: Timur Tabi
  Cc: McClintock Matthew-B29882, devicetree-discuss,
	linuxppc-dev@lists.ozlabs.org, linux-fbdev@vger.kernel.org
In-Reply-To: <4DBF0DF1.6050207@freescale.com>

On Mon, 2011-05-02 at 15:02 -0500, Timur Tabi wrote:
> McClintock Matthew-B29882 wrote:
> > Don't you have to spawn a terminal on the framebuffer for the login?
> 
> I suppose, but I don't know how to do that.  And although that would technically
> answer the question in the subject of this thread, I still would have *some*
> boot output on the serial port.  It would be nice if I could get all of stdout
> on the video display, and all of stdin from the serial port.

I don't think we have a way to do that unless you can make a serial
"keyboard" device in the input layer. The VT layer will only get its
input from such a thing, maybe that does exist in the depth of legacy
code in there but it has nothing to do with your device-tree.

> > Right now getty spawns the login on the serial port via /etc/inittab.
> > Something similiar is probably needed for the framebuffer.
> 
> getty appears to work only with serial devices, since it insists on a baud rate
> as one of the parameters.

No, or no existing distro would work :-)

Just fake a baudrate for the tty's

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Heiko Schocher @ 2011-05-03  5:17 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <20110502221406.GA15043@ponder.secretlab.ca>

Hello Grant,

Grant Likely wrote:
> On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
>> cc: Wolfram Sang <w.sang@pengutronix.de>
>> cc: Grant Likely <grant.likely@secretlab.ca>
>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> cc: linux-fbdev@vger.kernel.org
>> cc: devicetree-discuss@ozlabs.org
>> cc: Ben Dooks <ben@simtec.co.uk>
>> cc: Vincent Sanders <vince@simtec.co.uk>
>> cc: Samuel Ortiz <sameo@linux.intel.com>
>> cc: linux-kernel@vger.kernel.org
>> cc: Randy Dunlap <rdunlap@xenotime.net>
>> cc: Wolfgang Denk <wd@denx.de>
>> cc: Paul Mundt <lethal@linux-sh.org>
>>
>> changes since v5:
>> - repost complete patchseries, as Paul Mundt suggested
>> - rebased against current head
>> - add Acked-by from Samuel Ortiz (MFD parts)
>>   http://www.spinics.net/lists/linux-fbdev/msg02550.html
>>   http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.html
>>
>>   and Benjamin Herrenschmidt (DTS parts)
>>   http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279.html
>> - removed patch 
>>   "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board."
>>   therefore added
>>   "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board."
> 
> Refresh my memory, why was the mpc5200_defconfig updated dropped?

Because it is a board based on the tqm5200 board port ... no other
reason.

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Heiko Schocher @ 2011-05-03  5:27 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <BANLkTik3L28mmL=LGZ_0nV7vSOX9Miw3ow@mail.gmail.com>

Hello Grant,

Grant Likely wrote:
> On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca> wrote:
>> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>>> - add commandline options:
>>>   sm501fb.mode:
>>>     Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>>>   sm501fb.bpp:
>>>     Specify bit-per-pixel if not specified mode
>>>
>>> - Add support for encoding display mode information
>>>   in the device tree using verbatim EDID block.
>>>
>>>   If the "edid" entry in the "smi,sm501" node is present,
>>>   the driver will build mode database using EDID data
>>>   and allow setting the display modes from this database.
>>>
>>> Signed-off-by: Heiko Schocher <hs@denx.de>
>> Merged, thanks.
> 
> This patch causes the following build warning:

Hups ... when I posted the patch, it compiled clean ...

>   MODPOST vmlinux.o
> WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
> the function sm501fb_init_fb() to the variable
> .devinit.data:sm501_default_mode
> The function sm501fb_init_fb() references
> the variable __devinitdata sm501_default_mode.
> This is often because sm501fb_init_fb lacks a __devinitdata
> annotation or the annotation of sm501_default_mode is wrong.
> 
> WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
> the function sm501fb_init_fb() to the variable
> .devinit.data:sm501_default_mode
> The function sm501fb_init_fb() references
> the variable __devinitdata sm501_default_mode.
> This is often because sm501fb_init_fb lacks a __devinitdata
> annotation or the annotation of sm501_default_mode is wrong.
> 
> I've dropped the __devinitdata declaration in what I committed; can
> you investigate and post a fixup patch?

Of course, I look ASAP at it, thanks!
(Dummy question: where can I find your tree?)

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* Re: [PATCH 4/6] dt: generalize irq_of_create_mapping()
From: Benjamin Herrenschmidt @ 2011-05-03  1:50 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200203.8979.3569.stgit@ponder>

On Thu, 2011-04-28 at 14:02 -0600, Grant Likely wrote:
> This patch creates a common implementation of irq_of_create_mapping()
> and factors out the interrupt domain translation code from powerpc to
> make it available for all architectures.

I think you are going the wrong way around.

First thing first, is to make the irq domain / mapping API generic
without the OF bits.

IE. move the IRQ domain generically, get rid of irq_map by putting the
domain ptr & hw numbers in the irq desc/data etc...

Then you can move over the OF specific bits which are optional and
orthogonal to a large extent.

Cheers,
Ben.

> It creates a new structure, struct of_irq_domain, which can be
> embedded into the private data structure of an interrupt controller.
> Any interrupt controller can call of_irq_domain_add() to register a
> structure with a .map() hook that can translate irq specifiers from
> the device tree into linux irq numbers.
> 
> The patch also modifies the powerpc irq_host to embed the
> of_irq_domain structure and use the new common infrastructure for
> registering domains.  This separates the reverse mapping and irq
> allocation infrastructure of irq_host from the domain registration
> infrastructure.  I elected to split the functionality this way for
> several reasons.  First, with the major irq cleanup done by Thomas
> Gleixner, dynamic allocation of irqs can be handled gracefully with
> irq_alloc_desc*() and interrupt controllers may not need or want an
> irq_host layer to manage it for them.  For example, the new
> irq_chip_generic() already has a method for mapping between hwirq and
> Linux irq.
> 
> Second, the irq_host code currently has a lot of complexity to handle
> all the different reverse mapping types from a single structure.  The
> radix mapping in particular has a lot of support code, but only one
> user.  I didn't want to bring that complexity into the common code
> as-is.  Instead, I'd prefer to create a separate encapsulating
> structure for each revmap, and each type would have a separate .map
> hook.
> 
> For now, the mapping code remains powerpc-specific and further
> generalization will happen in subsequent patches.
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/microblaze/kernel/irq.c             |    7 --
>  arch/mips/kernel/prom.c                  |   14 ----
>  arch/powerpc/include/asm/irq.h           |   21 +++--
>  arch/powerpc/include/asm/irqhost.h       |    4 -
>  arch/powerpc/kernel/irq.c                |   99 ++++++++++++++-----------
>  arch/powerpc/platforms/cell/axon_msi.c   |   12 ++-
>  arch/powerpc/platforms/cell/spider-pic.c |    8 +-
>  arch/powerpc/sysdev/fsl_msi.c            |    2 -
>  arch/powerpc/sysdev/i8259.c              |    2 -
>  arch/powerpc/sysdev/ipic.c               |    2 -
>  arch/powerpc/sysdev/mpic.c               |    4 +
>  arch/powerpc/sysdev/mpic_msi.c           |    2 -
>  arch/powerpc/sysdev/mpic_pasemi_msi.c    |    4 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c       |    2 -
>  arch/x86/include/asm/irq_controller.h    |   12 ---
>  arch/x86/include/asm/prom.h              |    1 
>  arch/x86/kernel/devicetree.c             |   77 ++++----------------
>  drivers/of/irq.c                         |  118 ++++++++++++++++++++++++++++++
>  include/linux/of_irq.h                   |   31 ++++++++
>  19 files changed, 248 insertions(+), 174 deletions(-)
>  delete mode 100644 arch/x86/include/asm/irq_controller.h
> 
> diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c
> index ce7ac84..59bb560 100644
> --- a/arch/microblaze/kernel/irq.c
> +++ b/arch/microblaze/kernel/irq.c
> @@ -54,10 +54,3 @@ unsigned int irq_create_mapping(struct irq_host *host, irq_hw_number_t hwirq)
>  	return hwirq;
>  }
>  EXPORT_SYMBOL_GPL(irq_create_mapping);
> -
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	return intspec[0];
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
> index a19811e9..0b82f98 100644
> --- a/arch/mips/kernel/prom.c
> +++ b/arch/mips/kernel/prom.c
> @@ -60,20 +60,6 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
>  }
>  #endif
>  
> -/*
> - * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
> - *
> - * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
> - * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
> - * supported.
> - */
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	return intspec[0];
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> -
>  void __init early_init_devtree(void *params)
>  {
>  	/* Setup flat device-tree pointer */
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index a44be93..ccefc8c 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -55,11 +55,18 @@ typedef unsigned long irq_hw_number_t;
>   * model). It's the host callbacks that are responsible for setting the
>   * irq_chip on a given irq_desc after it's been mapped.
>   *
> + * irq_host builds upon the of_irq_domain code in drivers/of/irq.c.
> + * of_irq_domain provides all of the translation hooks for registering irq
> + * controllers. irq_host add mapping infrastructure to and from hardware
> + * irq numbers. IRQ controllers that don't need the mapping infrastructure
> + * can use irq_domain directly.
> + *
>   * The host code and data structures are fairly agnostic to the fact that
>   * we use an open firmware device-tree. We do have references to struct
> - * device_node in two places: in irq_find_host() to find the host matching
> - * a given interrupt controller node, and of course as an argument to its
> - * counterpart host->ops->match() callback. However, those are treated as
> + * device_node in two places: in of_irq_domain_find() to find the host matching
> + * a given interrupt controller node (which is actually common of_irq_domain
> + * code), and of course as an argument to its counterpart host->ops->match()
> + * and host->domain->match() callbacks. However, those are treated as
>   * generic pointers by the core and the fact that it's actually a device-node
>   * pointer is purely a convention between callers and implementation. This
>   * code could thus be used on other architectures by replacing those two
> @@ -137,14 +144,6 @@ extern struct irq_host *irq_alloc_host(struct device_node *of_node,
>  				       struct irq_host_ops *ops,
>  				       irq_hw_number_t inval_irq);
>  
> -
> -/**
> - * irq_find_host - Locates a host for a given device node
> - * @node: device-tree node of the interrupt controller
> - */
> -extern struct irq_host *irq_find_host(struct device_node *node);
> -
> -
>  /**
>   * irq_set_default_host - Set a "default" host
>   * @host: default host pointer
> diff --git a/arch/powerpc/include/asm/irqhost.h b/arch/powerpc/include/asm/irqhost.h
> index 958e6c1..a97a513 100644
> --- a/arch/powerpc/include/asm/irqhost.h
> +++ b/arch/powerpc/include/asm/irqhost.h
> @@ -8,6 +8,7 @@
>  
>  struct irq_host {
>  	struct list_head	link;
> +	struct of_irq_domain	domain;
>  
>  	/* type of reverse mapping technique */
>  	unsigned int		revmap_type;
> @@ -21,9 +22,6 @@ struct irq_host {
>  	struct irq_host_ops	*ops;
>  	void			*host_data;
>  	irq_hw_number_t		inval_irq;
> -
> -	/* Optional device node pointer */
> -	struct device_node	*of_node;
>  };
>  
>  #endif /* _ASM_POWERPC_IRQHOST_H */
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index b961b19..9300e1c 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -514,11 +514,40 @@ struct irq_host *virq_to_host(unsigned int virq)
>  }
>  EXPORT_SYMBOL_GPL(virq_to_host);
>  
> -static int default_irq_host_match(struct irq_host *h, struct device_node *np)
> +/**
> + * irq_host_domain_match() - irq_domain hook to call irq_host match ops.
> + *
> + * This functions gets set as the irq domain match function for irq_host
> + * instances *if* the ->ops->match() hook is populated.  If ->match() is
> + * not populated, then the default irq_domain matching behaviour is used
> + * instead.
> + */
> +static bool irq_host_domain_match(struct of_irq_domain *domain,
> +				  struct device_node *controller)
>  {
> -	return h->of_node != NULL && h->of_node == np;
> +	struct irq_host *host = container_of(domain, struct irq_host, domain);
> +	return host->ops->match(host, controller);
>  }
>  
> +static unsigned int irq_host_domain_map(struct of_irq_domain *domain,
> +					struct device_node *controller,
> +					const u32 *intspec,
> +					unsigned int intsize);
> +
> +/**
> + * irq_alloc_host() - Allocate and register an irq_host
> + * @of_node: Device node of the irq controller; this is used mainly as an
> + *           anonymouns context pointer.
> + * @revmap_type: One of IRQ_HOST_MAP_* defined in arch/powerpc/include/asm/irq.h
> + *               Defines the type of reverse map to be used by the irq_host.
> + * @revmap_arg: Currently only used by the IRQ_HOST_MAP_LINEAR which uses it
> + *              to define the size of the reverse map.
> + * @ops: irq_host ops structure for match/map/unmap/remap/xlate operations.
> + * @inval_irq: Value used by irq controller to indicate an invalid irq.
> + *
> + * irq_host implements mapping between hardware irq numbers and the linux
> + * virq number space.  This function allocates and registers an irq_host.
> + */
>  struct irq_host *irq_alloc_host(struct device_node *of_node,
>  				unsigned int revmap_type,
>  				unsigned int revmap_arg,
> @@ -542,10 +571,10 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	host->revmap_type = revmap_type;
>  	host->inval_irq = inval_irq;
>  	host->ops = ops;
> -	host->of_node = of_node_get(of_node);
> -
> -	if (host->ops->match == NULL)
> -		host->ops->match = default_irq_host_match;
> +	host->domain.controller = of_node_get(of_node);
> +	host->domain.map = irq_host_domain_map;
> +	if (host->ops->match != NULL)
> +		host->domain.match = irq_host_domain_match;
>  
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
>  
> @@ -561,7 +590,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  			 * instead of the current cruft
>  			 */
>  			if (mem_init_done) {
> -				of_node_put(host->of_node);
> +				of_node_put(host->domain.controller);
>  				kfree(host);
>  			}
>  			return NULL;
> @@ -572,6 +601,8 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	list_add(&host->link, &irq_hosts);
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  
> +	of_irq_domain_add(&host->domain);
> +
>  	/* Additional setups per revmap type */
>  	switch(revmap_type) {
>  	case IRQ_HOST_MAP_LEGACY:
> @@ -611,32 +642,12 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
>  	return host;
>  }
>  
> -struct irq_host *irq_find_host(struct device_node *node)
> -{
> -	struct irq_host *h, *found = NULL;
> -	unsigned long flags;
> -
> -	/* We might want to match the legacy controller last since
> -	 * it might potentially be set to match all interrupts in
> -	 * the absence of a device node. This isn't a problem so far
> -	 * yet though...
> -	 */
> -	raw_spin_lock_irqsave(&irq_big_lock, flags);
> -	list_for_each_entry(h, &irq_hosts, link)
> -		if (h->ops->match(h, node)) {
> -			found = h;
> -			break;
> -		}
> -	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
> -	return found;
> -}
> -EXPORT_SYMBOL_GPL(irq_find_host);
> -
>  void irq_set_default_host(struct irq_host *host)
>  {
>  	pr_debug("irq: Default host set to @0x%p\n", host);
>  
>  	irq_default_host = host;
> +	of_irq_set_default_domain(&host->domain);
>  }
>  
>  void irq_set_virq_count(unsigned int count)
> @@ -757,30 +768,29 @@ unsigned int irq_create_mapping(struct irq_host *host,
>  		return NO_IRQ;
>  
>  	printk(KERN_DEBUG "irq: irq %lu on host %s mapped to virtual irq %u\n",
> -		hwirq, host->of_node ? host->of_node->full_name : "null", virq);
> +		hwirq, host->domain.controller ? host->domain.controller->full_name : "null", virq);
>  
>  	return virq;
>  }
>  EXPORT_SYMBOL_GPL(irq_create_mapping);
>  
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> +/**
> + * irq_host_domain_map() - Map device tree irq to linux irq number
> + * This hook implements all of the powerpc 'irq_host' behaviour, which means
> + * - calling the ->ops->xlate hook to get the hardware irq number,
> + * - calling of_create_mapping to translate/allocate a linux virq number
> + * - calling irq_set_irq_type() if necessary
> + */
> +static unsigned int irq_host_domain_map(struct of_irq_domain *domain,
> +					struct device_node *controller,
> +					const u32 *intspec,
> +					unsigned int intsize)
>  {
> -	struct irq_host *host;
> +	struct irq_host *host = container_of(domain, struct irq_host, domain);
>  	irq_hw_number_t hwirq;
>  	unsigned int type = IRQ_TYPE_NONE;
>  	unsigned int virq;
>  
> -	if (controller == NULL)
> -		host = irq_default_host;
> -	else
> -		host = irq_find_host(controller);
> -	if (host == NULL) {
> -		printk(KERN_WARNING "irq: no irq host found for %s !\n",
> -		       controller->full_name);
> -		return NO_IRQ;
> -	}
> -
>  	/* If host has no translation, then we assume interrupt line */
>  	if (host->ops->xlate == NULL)
>  		hwirq = intspec[0];
> @@ -801,7 +811,6 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
>  		irq_set_irq_type(virq, type);
>  	return virq;
>  }
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
>  
>  void irq_dispose_mapping(unsigned int virq)
>  {
> @@ -1128,8 +1137,8 @@ static int virq_debug_show(struct seq_file *m, void *private)
>  				p = none;
>  			seq_printf(m, "%-15s  ", p);
>  
> -			if (irq_map[i].host && irq_map[i].host->of_node)
> -				p = irq_map[i].host->of_node->full_name;
> +			if (irq_map[i].host && irq_map[i].host->domain.controller)
> +				p = irq_map[i].host->domain.controller->full_name;
>  			else
>  				p = none;
>  			seq_printf(m, "%s\n", p);
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index e1469ae..f125673 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -152,7 +152,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
>  
>  static struct axon_msic *find_msi_translator(struct pci_dev *dev)
>  {
> -	struct irq_host *irq_host;
> +	struct of_irq_domain *irq_domain;
>  	struct device_node *dn, *tmp;
>  	const phandle *ph;
>  	struct axon_msic *msic = NULL;
> @@ -184,14 +184,14 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
>  		goto out_error;
>  	}
>  
> -	irq_host = irq_find_host(dn);
> -	if (!irq_host) {
> +	irq_domain = of_irq_domain_find(dn);
> +	if (!irq_domain) {
>  		dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
>  			dn->full_name);
>  		goto out_error;
>  	}
>  
> -	msic = irq_host->host_data;
> +	msic = irq_domain->priv;
>  
>  out_error:
>  	of_node_put(dn);
> @@ -336,7 +336,7 @@ static void axon_msi_shutdown(struct platform_device *device)
>  	u32 tmp;
>  
>  	pr_devel("axon_msi: disabling %s\n",
> -		  msic->irq_host->of_node->full_name);
> +		  msic->irq_host->domain.controller->full_name);
>  	tmp  = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
>  	tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
>  	msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
> @@ -399,7 +399,7 @@ static int axon_msi_probe(struct platform_device *device)
>  		goto out_free_fifo;
>  	}
>  
> -	msic->irq_host->host_data = msic;
> +	msic->irq_host->domain.priv = msic;
>  
>  	irq_set_handler_data(virq, msic);
>  	irq_set_chained_handler(virq, axon_msi_cascade);
> diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
> index 73a5494..5bf36ab 100644
> --- a/arch/powerpc/platforms/cell/spider-pic.c
> +++ b/arch/powerpc/platforms/cell/spider-pic.c
> @@ -236,18 +236,20 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
>  	 * tree in case the device-tree is ever fixed
>  	 */
>  	struct of_irq oirq;
> -	if (of_irq_map_one(pic->host->of_node, 0, &oirq) == 0) {
> +	if (of_irq_map_one(pic->host->domain.controller, 0, &oirq) == 0) {
>  		virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
>  					     oirq.size);
>  		return virq;
>  	}
>  
>  	/* Now do the horrible hacks */
> -	tmp = of_get_property(pic->host->of_node, "#interrupt-cells", NULL);
> +	tmp = of_get_property(pic->host->domain.controller,
> +				"#interrupt-cells", NULL);
>  	if (tmp == NULL)
>  		return NO_IRQ;
>  	intsize = *tmp;
> -	imap = of_get_property(pic->host->of_node, "interrupt-map", &imaplen);
> +	imap = of_get_property(pic->host->domain.controller,
> +				"interrupt-map", &imaplen);
>  	if (imap == NULL || imaplen < (intsize + 1))
>  		return NO_IRQ;
>  	iic = of_find_node_by_phandle(imap[intsize]);
> diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
> index 2c11b3e..b45a25a 100644
> --- a/arch/powerpc/sysdev/fsl_msi.c
> +++ b/arch/powerpc/sysdev/fsl_msi.c
> @@ -82,7 +82,7 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
>  	int rc;
>  
>  	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> -			      msi_data->irqhost->of_node);
> +			      msi_data->irqhost->domain.controller);
>  	if (rc)
>  		return rc;
>  
> diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
> index 30869f0..a6f78fb 100644
> --- a/arch/powerpc/sysdev/i8259.c
> +++ b/arch/powerpc/sysdev/i8259.c
> @@ -166,7 +166,7 @@ static struct resource pic_edgectrl_iores = {
>  
>  static int i8259_host_match(struct irq_host *h, struct device_node *node)
>  {
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int i8259_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index fc3751f..5805c7b 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -676,7 +676,7 @@ static struct irq_chip ipic_edge_irq_chip = {
>  static int ipic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless ipic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int ipic_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 6e9e594..cafc364 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -956,7 +956,7 @@ static struct irq_chip mpic_irq_ht_chip = {
>  static int mpic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless mpic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int mpic_host_map(struct irq_host *h, unsigned int virq,
> @@ -1296,7 +1296,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
>  
>  	BUG_ON(isu_num >= MPIC_MAX_ISU);
>  
> -	mpic_map(mpic, mpic->irqhost->of_node,
> +	mpic_map(mpic, mpic->irqhost->domain.controller,
>  		 paddr, &mpic->isus[isu_num], 0,
>  		 MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
>  
> diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
> index 50176ed..ddf79c7 100644
> --- a/arch/powerpc/sysdev/mpic_msi.c
> +++ b/arch/powerpc/sysdev/mpic_msi.c
> @@ -85,7 +85,7 @@ int mpic_msi_init_allocator(struct mpic *mpic)
>  	int rc;
>  
>  	rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
> -			      mpic->irqhost->of_node);
> +			      mpic->irqhost->domain.controller);
>  	if (rc)
>  		return rc;
>  
> diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> index 6b11a89..857be51 100644
> --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
> +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> @@ -153,8 +153,8 @@ int mpic_pasemi_msi_init(struct mpic *mpic)
>  {
>  	int rc;
>  
> -	if (!mpic->irqhost->of_node ||
> -	    !of_device_is_compatible(mpic->irqhost->of_node,
> +	if (!mpic->irqhost->domain.controller ||
> +	    !of_device_is_compatible(mpic->irqhost->domain.controller,
>  				     "pasemi,pwrficient-openpic"))
>  		return -ENODEV;
>  
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> index 9dd7746..c2ccafa 100644
> --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -250,7 +250,7 @@ static struct irq_chip qe_ic_irq_chip = {
>  static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
>  {
>  	/* Exact match, unless qe_ic node is NULL */
> -	return h->of_node == NULL || h->of_node == node;
> +	return h->domain.controller == NULL || h->domain.controller == node;
>  }
>  
>  static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
> diff --git a/arch/x86/include/asm/irq_controller.h b/arch/x86/include/asm/irq_controller.h
> deleted file mode 100644
> index 423bbbd..0000000
> --- a/arch/x86/include/asm/irq_controller.h
> +++ /dev/null
> @@ -1,12 +0,0 @@
> -#ifndef __IRQ_CONTROLLER__
> -#define __IRQ_CONTROLLER__
> -
> -struct irq_domain {
> -	int (*xlate)(struct irq_domain *h, const u32 *intspec, u32 intsize,
> -			u32 *out_hwirq, u32 *out_type);
> -	void *priv;
> -	struct device_node *controller;
> -	struct list_head l;
> -};
> -
> -#endif
> diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
> index 971e0b4..eb9d5ab 100644
> --- a/arch/x86/include/asm/prom.h
> +++ b/arch/x86/include/asm/prom.h
> @@ -21,7 +21,6 @@
>  #include <asm/irq.h>
>  #include <asm/atomic.h>
>  #include <asm/setup.h>
> -#include <asm/irq_controller.h>
>  
>  #ifdef CONFIG_OF
>  extern int of_ioapic;
> diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> index 706a9fb..651e724 100644
> --- a/arch/x86/kernel/devicetree.c
> +++ b/arch/x86/kernel/devicetree.c
> @@ -15,64 +15,14 @@
>  #include <linux/of_pci.h>
>  
>  #include <asm/hpet.h>
> -#include <asm/irq_controller.h>
>  #include <asm/apic.h>
>  #include <asm/pci_x86.h>
>  
>  __initdata u64 initial_dtb;
>  char __initdata cmd_line[COMMAND_LINE_SIZE];
> -static LIST_HEAD(irq_domains);
> -static DEFINE_RAW_SPINLOCK(big_irq_lock);
>  
>  int __initdata of_ioapic;
>  
> -#ifdef CONFIG_X86_IO_APIC
> -static void add_interrupt_host(struct irq_domain *ih)
> -{
> -	unsigned long flags;
> -
> -	raw_spin_lock_irqsave(&big_irq_lock, flags);
> -	list_add(&ih->l, &irq_domains);
> -	raw_spin_unlock_irqrestore(&big_irq_lock, flags);
> -}
> -#endif
> -
> -static struct irq_domain *get_ih_from_node(struct device_node *controller)
> -{
> -	struct irq_domain *ih, *found = NULL;
> -	unsigned long flags;
> -
> -	raw_spin_lock_irqsave(&big_irq_lock, flags);
> -	list_for_each_entry(ih, &irq_domains, l) {
> -		if (ih->controller ==  controller) {
> -			found = ih;
> -			break;
> -		}
> -	}
> -	raw_spin_unlock_irqrestore(&big_irq_lock, flags);
> -	return found;
> -}
> -
> -unsigned int irq_create_of_mapping(struct device_node *controller,
> -				   const u32 *intspec, unsigned int intsize)
> -{
> -	struct irq_domain *ih;
> -	u32 virq, type;
> -	int ret;
> -
> -	ih = get_ih_from_node(controller);
> -	if (!ih)
> -		return 0;
> -	ret = ih->xlate(ih, intspec, intsize, &virq, &type);
> -	if (ret)
> -		return 0;
> -	if (type == IRQ_TYPE_NONE)
> -		return virq;
> -	irq_set_irq_type(virq, type);
> -	return virq;
> -}
> -EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> -
>  unsigned long pci_address_to_pio(phys_addr_t address)
>  {
>  	/*
> @@ -366,32 +316,33 @@ static struct of_ioapic_type of_ioapic_type[] =
>  	},
>  };
>  
> -static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
> -			u32 *out_hwirq, u32 *out_type)
> +static unsigned int ioapic_of_irq_map(struct of_irq_domain *id,
> +				      struct device_node *np,
> +				      const u32 *intspec, u32 intsize)
>  {
>  	struct io_apic_irq_attr attr;
>  	struct of_ioapic_type *it;
> -	u32 line, idx, type;
> +	u32 line, idx, type, hwirq;
>  
>  	if (intsize < 2)
> -		return -EINVAL;
> +		return 0;
>  
>  	line = *intspec;
>  	idx = (u32) id->priv;
> -	*out_hwirq = line + mp_gsi_routing[idx].gsi_base;
> +	hwirq = line + mp_gsi_routing[idx].gsi_base;
>  
>  	intspec++;
>  	type = *intspec;
>  
>  	if (type >= ARRAY_SIZE(of_ioapic_type))
> -		return -EINVAL;
> +		return 0;
>  
>  	it = of_ioapic_type + type;
> -	*out_type = it->out_type;
> -
>  	set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
>  
> -	return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr);
> +	if (io_apic_setup_irq_pin(hwirq, cpu_to_node(0), &attr))
> +		return 0;
> +	return hwirq;
>  }
>  
>  static void __init ioapic_add_ofnode(struct device_node *np)
> @@ -408,14 +359,14 @@ static void __init ioapic_add_ofnode(struct device_node *np)
>  
>  	for (i = 0; i < nr_ioapics; i++) {
>  		if (r.start == mp_ioapics[i].apicaddr) {
> -			struct irq_domain *id;
> +			struct of_irq_domain *id;
>  
>  			id = kzalloc(sizeof(*id), GFP_KERNEL);
>  			BUG_ON(!id);
> -			id->controller = np;
> -			id->xlate = ioapic_xlate;
> +			id->controller = of_node_get(np);
> +			id->map = ioapic_of_irq_map;
>  			id->priv = (void *)i;
> -			add_interrupt_host(id);
> +			of_irq_domain_add(id);
>  			return;
>  		}
>  	}
> diff --git a/drivers/of/irq.c b/drivers/of/irq.c
> index 75b0d3c..6da0964 100644
> --- a/drivers/of/irq.c
> +++ b/drivers/of/irq.c
> @@ -19,6 +19,7 @@
>   */
>  
>  #include <linux/errno.h>
> +#include <linux/list.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/of_irq.h>
> @@ -29,6 +30,123 @@
>  #define NO_IRQ 0
>  #endif
>  
> +/*
> + * Device Tree IRQ domains
> + *
> + * IRQ domains provide translation from device tree irq controller nodes to
> + * linux IRQ numbers.  IRQ controllers register an irq_domain with a .map()
> + * hook that performs everything needed to decode and configure a device
> + * tree specified interrupt.
> + */
> +static LIST_HEAD(of_irq_domains);
> +static DEFINE_RAW_SPINLOCK(of_irq_lock);
> +static struct of_irq_domain *of_irq_default_domain;
> +
> +/**
> + * of_irq_domain_default_match() - Return true if the controller pointers match
> + *
> + * Default match behaviour for of_irq_domains.  If the device tree node pointer
> + * matches the value stored in the domain structure, then return true.
> + */
> +static bool of_irq_domain_default_match(struct of_irq_domain *domain,
> +					struct device_node *controller)
> +{
> +	return domain->controller == controller;
> +}
> +
> +/**
> + * of_irq_domain_add() - Register a device tree irq domain
> + * @domain: pointer to domain structure to be registered.
> + *
> + * Adds an of_irq_domain to the global list of domains.
> + */
> +void of_irq_domain_add(struct of_irq_domain *domain)
> +{
> +	unsigned long flags;
> +
> +	if (!domain->match)
> +		domain->match = of_irq_domain_default_match;
> +	if (!domain->map) {
> +		WARN_ON(1);
> +		return;
> +	}
> +
> +	raw_spin_lock_irqsave(&of_irq_lock, flags);
> +	list_add(&domain->list, &of_irq_domains);
> +	raw_spin_unlock_irqrestore(&of_irq_lock, flags);
> +}
> +
> +/**
> + * of_irq_domain_find() - Find the domain that handles a given device tree node
> + *
> + * Returns the pointer to an of_irq_domain capable of translating irq specifiers
> + * for the given irq controller device tree node.  Returns NULL if a suitable
> + * domain could not be found.
> + */
> +struct of_irq_domain *of_irq_domain_find(struct device_node *controller)
> +{
> +	struct of_irq_domain *domain, *found = NULL;
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&of_irq_lock, flags);
> +	list_for_each_entry(domain, &of_irq_domains, list) {
> +		if (domain->match(domain, controller)) {
> +			found = domain;
> +			break;
> +		}
> +	}
> +	raw_spin_unlock_irqrestore(&of_irq_lock, flags);
> +	return found;
> +}
> +
> +/**
> + * of_irq_set_default_domain() - Set a "default" host
> + * @domain: default domain pointer
> + *
> + * For convenience, it's possible to set a "default" host that will be used
> + * whenever NULL is passed to irq_of_create_mapping(). It makes life easier
> + * for platforms that want to manipulate a few hard coded interrupt numbers
> + * that aren't properly represented in the device-tree.
> + */
> +void of_irq_set_default_domain(struct of_irq_domain *domain)
> +{
> +	pr_debug("irq: Default host set to @0x%p\n", domain);
> +	of_irq_default_domain = domain;
> +}
> +
> +/**
> + * irq_create_of_mapping() - Map a linux irq # from a device tree specifier
> + * @controller - interrupt-controller node in the device tree
> + * @intspec - array of interrupt specifier data.  Points to an array of u32
> + *            values.  Data is *cpu-native* endian u32 values.
> + * @intsize - size of intspec array.
> + *
> + * Given an interrupt controller node pointer and an interrupt specifier, this
> + * function looks up the linux irq number.
> + */
> +unsigned int irq_create_of_mapping(struct device_node *controller,
> +				   const u32 *intspec, unsigned int intsize)
> +{
> +	struct of_irq_domain *domain;
> +
> +	domain = of_irq_domain_find(controller);
> +	if (!domain)
> +		domain = of_irq_default_domain;
> +	if (!domain) {
> +		pr_warn("error: no irq host found for %s !\n",
> +			controller->full_name);
> +#if defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE)
> +		/* FIXME: make Microblaze and MIPS register irq domains */
> +		return intspec[0];
> +#else /* defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE) */
> +		return NO_IRQ;
> +#endif /* defined(CONFIG_MIPS) || defined(CONFIG_MICROBLAZE) */
> +	}
> +
> +	return domain->map(domain, controller, intspec, intsize);
> +}
> +EXPORT_SYMBOL_GPL(irq_create_of_mapping);
> +
>  /**
>   * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
>   * @device: Device node of the device whose interrupt is to be mapped
> diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
> index 109e013..511dbc3 100644
> --- a/include/linux/of_irq.h
> +++ b/include/linux/of_irq.h
> @@ -33,6 +33,37 @@ struct of_irq {
>  	u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */
>  };
>  
> +/**
> + * struct of_irq_domain - Translation domain from device tree to linux irq
> + * @list: Linked list node entry
> + * @match: (optional) Called to determine if the passed device_node
> + *         interrupt-controller can be translated by this irq domain.
> + *         Returns 'true' if it can.
> + * @decode: Translation callback; returns virq, or NO_IRQ if this irq
> + *          domain cannot translate it.
> + * @controller: (optional) pointer to OF node.  By default, if
> + *              'match' is not set, then this of_irq_domain will only
> + *              be used if the device tree node passed in matches the
> + *              controller pointer.
> + * @priv: Private data pointer, not touched by core of_irq_domain code.
> + */
> +struct of_irq_domain {
> +	struct list_head list;
> +	bool (*match)(struct of_irq_domain *d, struct device_node *np);
> +	unsigned int (*map)(struct of_irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, u32 intsize);
> +	struct device_node *controller;
> +	void *priv;
> +};
> +
> +/**
> + * of_irq_domain_add() - Add a device tree interrupt translation domain
> + * @domain: interrupt domain to add.
> + */
> +extern void of_irq_domain_add(struct of_irq_domain *domain);
> +extern void of_irq_set_default_domain(struct of_irq_domain *host);
> +extern struct of_irq_domain *of_irq_domain_find(struct device_node *controller);
> +
>  /*
>   * Workarounds only applied to 32bit powermac machines
>   */

^ permalink raw reply

* Re: [PATCH 3/6] powerpc: Make struct irq_host semi-private by moving into irqhost.h
From: Benjamin Herrenschmidt @ 2011-05-03  1:48 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200158.8979.39548.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> Very few files actually need direct access to struct irq_host members.
> This patch moves the irq_host definition into another file so that it
> isn't brought in by default, and to prepare for the addition of
> struct of_irq_domain, which will factor some of the irq_host behaviour
> out into common code.  This needs to be done because of_irq_domain
> will be embedded inside struct irq_host, and to do that it needs to be
> guaranteed that struct of_irq_domain gets fully defined first.

Why do you want to separate the irq "host" as used by powerpc with the
generic irq domain ? They should be one single thing...

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/powerpc/include/asm/irq.h                   |   20 +--------------
>  arch/powerpc/include/asm/irqhost.h               |   29 ++++++++++++++++++++++
>  arch/powerpc/kernel/irq.c                        |    1 +
>  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    1 +
>  arch/powerpc/platforms/52xx/media5200.c          |    1 +
>  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 +
>  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |    1 +
>  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    1 +
>  arch/powerpc/platforms/cell/axon_msi.c           |    1 +
>  arch/powerpc/platforms/cell/spider-pic.c         |    1 +
>  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    1 +
>  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    1 +
>  arch/powerpc/platforms/embedded6xx/wii.c         |    6 +++--
>  arch/powerpc/sysdev/fsl_msi.c                    |    1 +
>  arch/powerpc/sysdev/i8259.c                      |    1 +
>  arch/powerpc/sysdev/ipic.c                       |    1 +
>  arch/powerpc/sysdev/mpc8xxx_gpio.c               |    1 +
>  arch/powerpc/sysdev/mpic.c                       |    1 +
>  arch/powerpc/sysdev/mpic_msi.c                   |    1 +
>  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    1 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    1 +
>  arch/powerpc/sysdev/uic.c                        |    1 +
>  arch/powerpc/sysdev/xilinx_intc.c                |    1 +
>  23 files changed, 54 insertions(+), 21 deletions(-)
>  create mode 100644 arch/powerpc/include/asm/irqhost.h
> 
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index 4d2cc6f..a44be93 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -104,29 +104,11 @@ struct irq_host_ops {
>  		     irq_hw_number_t *out_hwirq, unsigned int *out_type);
>  };
>  
> -struct irq_host {
> -	struct list_head	link;
> -
> -	/* type of reverse mapping technique */
> -	unsigned int		revmap_type;
> +/* Reverse map types; pass into irq_alloc_host revmap_type argument */
>  #define IRQ_HOST_MAP_LEGACY     0 /* legacy 8259, gets irqs 1..15 */
>  #define IRQ_HOST_MAP_NOMAP	1 /* no fast reverse mapping */
>  #define IRQ_HOST_MAP_LINEAR	2 /* linear map of interrupts */
>  #define IRQ_HOST_MAP_TREE	3 /* radix tree */
> -	union {
> -		struct {
> -			unsigned int size;
> -			unsigned int *revmap;
> -		} linear;
> -		struct radix_tree_root tree;
> -	} revmap_data;
> -	struct irq_host_ops	*ops;
> -	void			*host_data;
> -	irq_hw_number_t		inval_irq;
> -
> -	/* Optional device node pointer */
> -	struct device_node	*of_node;
> -};
>  
>  struct irq_data;
>  extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
> diff --git a/arch/powerpc/include/asm/irqhost.h b/arch/powerpc/include/asm/irqhost.h
> new file mode 100644
> index 0000000..958e6c1
> --- /dev/null
> +++ b/arch/powerpc/include/asm/irqhost.h
> @@ -0,0 +1,29 @@
> +#ifndef _ASM_POWERPC_IRQHOST_H
> +#define _ASM_POWERPC_IRQHOST_H
> +
> +#include <linux/list.h>
> +#include <linux/radix-tree.h>
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +
> +struct irq_host {
> +	struct list_head	link;
> +
> +	/* type of reverse mapping technique */
> +	unsigned int		revmap_type;
> +	union {
> +		struct {
> +			unsigned int size;
> +			unsigned int *revmap;
> +		} linear;
> +		struct radix_tree_root tree;
> +	} revmap_data;
> +	struct irq_host_ops	*ops;
> +	void			*host_data;
> +	irq_hw_number_t		inval_irq;
> +
> +	/* Optional device node pointer */
> +	struct device_node	*of_node;
> +};
> +
> +#endif /* _ASM_POWERPC_IRQHOST_H */
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 5ccf38f..b961b19 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -56,6 +56,7 @@
>  #include <linux/of.h>
>  #include <linux/of_irq.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/uaccess.h>
>  #include <asm/system.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> index a8bc0d4..162bbb7 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
> @@ -18,6 +18,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/io.h>
> +#include <asm/irqhost.h>
>  #include <asm/prom.h>
>  
>  static struct device_node *cpld_pic_node;
> diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
> index 96f85e5..e03f2cb 100644
> --- a/arch/powerpc/platforms/52xx/media5200.c
> +++ b/arch/powerpc/platforms/52xx/media5200.c
> @@ -25,6 +25,7 @@
>  #include <linux/irq.h>
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
> +#include <asm/irqhost.h>
>  #include <asm/time.h>
>  #include <asm/prom.h>
>  #include <asm/machdep.h>
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> index 6c39b9c..55b2d26 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
> @@ -67,6 +67,7 @@
>  #include <linux/watchdog.h>
>  #include <linux/miscdevice.h>
>  #include <linux/uaccess.h>
> +#include <asm/irqhost.h>
>  #include <asm/div64.h>
>  #include <asm/mpc52xx.h>
>  
> diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> index bb61181..65bbfd1 100644
> --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
> @@ -101,6 +101,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/mpc52xx.h>
> diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> index 5d6c34c..0ca79e0 100644
> --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
> @@ -19,6 +19,7 @@
>  #include <linux/bootmem.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/cpm2.h>
> diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
> index 1e3329e..e1469ae 100644
> --- a/arch/powerpc/platforms/cell/axon_msi.c
> +++ b/arch/powerpc/platforms/cell/axon_msi.c
> @@ -17,6 +17,7 @@
>  #include <linux/debugfs.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/dcr.h>
>  #include <asm/machdep.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
> index 34d2b99..73a5494 100644
> --- a/arch/powerpc/platforms/cell/spider-pic.c
> +++ b/arch/powerpc/platforms/cell/spider-pic.c
> @@ -24,6 +24,7 @@
>  #include <linux/irq.h>
>  #include <linux/ioport.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/pgtable.h>
>  #include <asm/prom.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> index 77cbe4c..1b60a34 100644
> --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
> @@ -18,6 +18,7 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  
>  #include "flipper-pic.h"
> diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> index 44b398b..4f87661 100644
> --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
> @@ -18,6 +18,7 @@
>  #include <linux/init.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  
>  #include "hlwd-pic.h"
> diff --git a/arch/powerpc/platforms/embedded6xx/wii.c b/arch/powerpc/platforms/embedded6xx/wii.c
> index 1b5dc1a..c9176a9 100644
> --- a/arch/powerpc/platforms/embedded6xx/wii.c
> +++ b/arch/powerpc/platforms/embedded6xx/wii.c
> @@ -85,9 +85,11 @@ void __init wii_memory_fixups(void)
>  	wii_hole_start = p[0].base + p[0].size;
>  	wii_hole_size = p[1].base - wii_hole_start;
>  
> -	pr_info("MEM1: <%08llx %08llx>\n", p[0].base, p[0].size);
> +	pr_info("MEM1: <%08llx %08llx>\n",
> +		(unsigned long long)p[0].base, (unsigned long long)p[0].size);
>  	pr_info("HOLE: <%08lx %08lx>\n", wii_hole_start, wii_hole_size);
> -	pr_info("MEM2: <%08llx %08llx>\n", p[1].base, p[1].size);
> +	pr_info("MEM2: <%08llx %08llx>\n",
> +		(unsigned long long)p[1].base, (unsigned long long)p[1].size);
>  
>  	p[0].size += wii_hole_size + p[1].size;
>  
> diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
> index d5679dc..2c11b3e 100644
> --- a/arch/powerpc/sysdev/fsl_msi.c
> +++ b/arch/powerpc/sysdev/fsl_msi.c
> @@ -19,6 +19,7 @@
>  #include <linux/slab.h>
>  #include <linux/of_platform.h>
>  #include <sysdev/fsl_soc.h>
> +#include <asm/irqhost.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
>  #include <asm/ppc-pci.h>
> diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
> index 142770c..30869f0 100644
> --- a/arch/powerpc/sysdev/i8259.c
> +++ b/arch/powerpc/sysdev/i8259.c
> @@ -13,6 +13,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel.h>
>  #include <linux/delay.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/i8259.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
> index f0ece79..fc3751f 100644
> --- a/arch/powerpc/sysdev/ipic.c
> +++ b/arch/powerpc/sysdev/ipic.c
> @@ -24,6 +24,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/fsl_devices.h>
>  #include <asm/irq.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/ipic.h>
> diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> index fb4963a..f6839a7 100644
> --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
> +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> @@ -17,6 +17,7 @@
>  #include <linux/gpio.h>
>  #include <linux/slab.h>
>  #include <linux/irq.h>
> +#include <asm/irqhost.h>
>  
>  #define MPC8XXX_GPIO_PINS	32
>  
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index 824a94f..6e9e594 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -28,6 +28,7 @@
>  #include <linux/pci.h>
>  #include <linux/slab.h>
>  
> +#include <asm/irqhost.h>
>  #include <asm/ptrace.h>
>  #include <asm/signal.h>
>  #include <asm/io.h>
> diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
> index 0f67cd7..50176ed 100644
> --- a/arch/powerpc/sysdev/mpic_msi.c
> +++ b/arch/powerpc/sysdev/mpic_msi.c
> @@ -11,6 +11,7 @@
>  #include <linux/irq.h>
>  #include <linux/bitmap.h>
>  #include <linux/msi.h>
> +#include <asm/irqhost.h>
>  #include <asm/mpic.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
> diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> index 38e6238..6b11a89 100644
> --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
> +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
> @@ -18,6 +18,7 @@
>  #include <linux/irq.h>
>  #include <linux/bootmem.h>
>  #include <linux/msi.h>
> +#include <asm/irqhost.h>
>  #include <asm/mpic.h>
>  #include <asm/prom.h>
>  #include <asm/hw_irq.h>
> diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> index b2acda0..9dd7746 100644
> --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
> +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
> @@ -26,6 +26,7 @@
>  #include <linux/device.h>
>  #include <linux/bootmem.h>
>  #include <linux/spinlock.h>
> +#include <asm/irqhost.h>
>  #include <asm/irq.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
> diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
> index 984cd20..a097f4c 100644
> --- a/arch/powerpc/sysdev/uic.c
> +++ b/arch/powerpc/sysdev/uic.c
> @@ -26,6 +26,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/kernel_stat.h>
>  #include <asm/irq.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/prom.h>
>  #include <asm/dcr.h>
> diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
> index 6183799..28d4ded 100644
> --- a/arch/powerpc/sysdev/xilinx_intc.c
> +++ b/arch/powerpc/sysdev/xilinx_intc.c
> @@ -23,6 +23,7 @@
>  #include <linux/kernel.h>
>  #include <linux/irq.h>
>  #include <linux/of.h>
> +#include <asm/irqhost.h>
>  #include <asm/io.h>
>  #include <asm/processor.h>
>  #include <asm/i8259.h>

^ permalink raw reply

* Re: [PATCH 2/6] powerpc: make irq_{alloc, free}_virt private and remove count argument
From: Benjamin Herrenschmidt @ 2011-05-03  1:47 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200153.8979.23873.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> irq_alloc_virt() and irq_free_virt() aren't called anywhere but from
> arch/powerpc/kernel/irq.c, and they are only ever called with count=1.
> This patch removes the prototypes from the header file, removes the
> count arguments, and cuts out the dead code.
> 
> Also removes obsolete references to irq_early_init()

Nack.

The count was intended to be able to allocate blocks of interrupts. This
was not used so far because we didn't support MSI blocks (for non-X
MSIs) but that is coming, and unfortunately, the API that was designed
for that is crap and requires contiguous IRQ numbers on the linux side
as well as on the device side (well device side is a HW requirement but
we could have been smarter on the Linux side).

So the ability to allocate blocks will be needed. In fact it's not clear
yet whether we'll also need them to be naturally aligned powers of two
or not at this stage. It depends how the bloody API is going to be used
by drivers.

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  arch/microblaze/kernel/setup.c |    2 -
>  arch/powerpc/include/asm/irq.h |   32 ----------------
>  arch/powerpc/kernel/irq.c      |   82 ++++++++++++++++++++--------------------
>  3 files changed, 40 insertions(+), 76 deletions(-)
> 
> diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
> index 8e2c09b..19d3ab7 100644
> --- a/arch/microblaze/kernel/setup.c
> +++ b/arch/microblaze/kernel/setup.c
> @@ -51,8 +51,6 @@ void __init setup_arch(char **cmdline_p)
>  
>  	unflatten_device_tree();
>  
> -	/* NOTE I think that this function is not necessary to call */
> -	/* irq_early_init(); */
>  	setup_cpuinfo();
>  
>  	microblaze_cache_init();
> diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
> index e1983d5..4d2cc6f 100644
> --- a/arch/powerpc/include/asm/irq.h
> +++ b/arch/powerpc/include/asm/irq.h
> @@ -264,38 +264,6 @@ extern unsigned int irq_linear_revmap(struct irq_host *host,
>  				      irq_hw_number_t hwirq);
>  
> 
> -
> -/**
> - * irq_alloc_virt - Allocate virtual irq numbers
> - * @host: host owning these new virtual irqs
> - * @count: number of consecutive numbers to allocate
> - * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
> - *
> - * This is a low level function that is used internally by irq_create_mapping()
> - * and that can be used by some irq controllers implementations for things
> - * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
> - */
> -extern unsigned int irq_alloc_virt(struct irq_host *host,
> -				   unsigned int count,
> -				   unsigned int hint);
> -
> -/**
> - * irq_free_virt - Free virtual irq numbers
> - * @virq: virtual irq number of the first interrupt to free
> - * @count: number of interrupts to free
> - *
> - * This function is the opposite of irq_alloc_virt. It will not clear reverse
> - * maps, this should be done previously by unmap'ing the interrupt. In fact,
> - * all interrupts covered by the range being freed should have been unmapped
> - * prior to calling this.
> - */
> -extern void irq_free_virt(unsigned int virq, unsigned int count);
> -
> -/**
> - * irq_early_init - Init irq remapping subsystem
> - */
> -extern void irq_early_init(void);
> -
>  static __inline__ int irq_canonicalize(int irq)
>  {
>  	return irq;
> diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
> index 422672b..5ccf38f 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -647,6 +647,9 @@ void irq_set_virq_count(unsigned int count)
>  		irq_virq_count = count;
>  }
>  
> +static unsigned int irq_alloc_virt(struct irq_host *host, unsigned int hint);
> +static void irq_free_virt(unsigned int virq);
> +
>  static int irq_setup_virq(struct irq_host *host, unsigned int virq,
>  			    irq_hw_number_t hwirq)
>  {
> @@ -675,7 +678,7 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
>  errdesc:
>  	irq_free_descs(virq, 1);
>  error:
> -	irq_free_virt(virq, 1);
> +	irq_free_virt(virq);
>  	return -1;
>  }
>  
> @@ -689,7 +692,7 @@ unsigned int irq_create_direct_mapping(struct irq_host *host)
>  	BUG_ON(host == NULL);
>  	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
>  
> -	virq = irq_alloc_virt(host, 1, 0);
> +	virq = irq_alloc_virt(host, 0);
>  	if (virq == NO_IRQ) {
>  		pr_debug("irq: create_direct virq allocation failed\n");
>  		return NO_IRQ;
> @@ -742,7 +745,7 @@ unsigned int irq_create_mapping(struct irq_host *host,
>  	} else {
>  		/* Allocate a virtual interrupt number */
>  		hint = hwirq % irq_virq_count;
> -		virq = irq_alloc_virt(host, 1, hint);
> +		virq = irq_alloc_virt(host, hint);
>  		if (virq == NO_IRQ) {
>  			pr_debug("irq: -> virq allocation failed\n");
>  			return NO_IRQ;
> @@ -856,7 +859,7 @@ void irq_dispose_mapping(unsigned int virq)
>  
>  	irq_free_descs(virq, 1);
>  	/* Free it */
> -	irq_free_virt(virq, 1);
> +	irq_free_virt(virq);
>  }
>  EXPORT_SYMBOL_GPL(irq_dispose_mapping);
>  
> @@ -974,36 +977,31 @@ unsigned int irq_linear_revmap(struct irq_host *host,
>  	return revmap[hwirq];
>  }
>  
> -unsigned int irq_alloc_virt(struct irq_host *host,
> -			    unsigned int count,
> -			    unsigned int hint)
> +/**
> + * irq_alloc_virt() - Allocate virtual irq numbers
> + * @host: host owning these new virtual irqs
> + * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
> + *
> + * This is a low level function that is used internally by irq_create_mapping()
> + */
> +static unsigned int irq_alloc_virt(struct irq_host *host, unsigned int hint)
>  {
>  	unsigned long flags;
>  	unsigned int i, j, found = NO_IRQ;
>  
> -	if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
> -		return NO_IRQ;
> -
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
>  
>  	/* Use hint for 1 interrupt if any */
> -	if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&
> +	if (hint >= NUM_ISA_INTERRUPTS &&
>  	    hint < irq_virq_count && irq_map[hint].host == NULL) {
>  		found = hint;
>  		goto hint_found;
>  	}
>  
> -	/* Look for count consecutive numbers in the allocatable
> -	 * (non-legacy) space
> -	 */
> +	/* Look for a free virq in the allocatable (non-legacy) space */
>  	for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
> -		if (irq_map[i].host != NULL)
> -			j = 0;
> -		else
> -			j++;
> -
> -		if (j == count) {
> -			found = i - count + 1;
> +		if (irq_map[i].host == NULL) {
> +			found = i;
>  			break;
>  		}
>  	}
> @@ -1012,36 +1010,36 @@ unsigned int irq_alloc_virt(struct irq_host *host,
>  		return NO_IRQ;
>  	}
>   hint_found:
> -	for (i = found; i < (found + count); i++) {
> -		irq_map[i].hwirq = host->inval_irq;
> -		smp_wmb();
> -		irq_map[i].host = host;
> -	}
> +	irq_map[found].hwirq = host->inval_irq;
> +	smp_wmb();
> +	irq_map[found].host = host;
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  	return found;
>  }
>  
> -void irq_free_virt(unsigned int virq, unsigned int count)
> +/**
> + * irq_free_virt() - Free virtual irq numbers
> + * @virq: virtual irq number of the first interrupt to free
> + *
> + * This function is the opposite of irq_alloc_virt. It will not clear reverse
> + * maps, this should be done previously by unmap'ing the interrupt. In fact,
> + * the interrupts being freed should have been unmapped prior to calling this.
> + */
> +static void irq_free_virt(unsigned int virq)
>  {
>  	unsigned long flags;
> -	unsigned int i;
> +	struct irq_host *host;
>  
> -	WARN_ON (virq < NUM_ISA_INTERRUPTS);
> -	WARN_ON (count == 0 || (virq + count) > irq_virq_count);
> +	if ((virq < NUM_ISA_INTERRUPTS) || (virq >= irq_virq_count)) {
> +		WARN_ON(1);
> +		return;
> +	}
>  
>  	raw_spin_lock_irqsave(&irq_big_lock, flags);
> -	for (i = virq; i < (virq + count); i++) {
> -		struct irq_host *host;
> -
> -		if (i < NUM_ISA_INTERRUPTS ||
> -		    (virq + count) > irq_virq_count)
> -			continue;
> -
> -		host = irq_map[i].host;
> -		irq_map[i].hwirq = host->inval_irq;
> -		smp_wmb();
> -		irq_map[i].host = NULL;
> -	}
> +	host = irq_map[virq].host;
> +	irq_map[virq].hwirq = host->inval_irq;
> +	smp_wmb();
> +	irq_map[virq].host = NULL;
>  	raw_spin_unlock_irqrestore(&irq_big_lock, flags);
>  }
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH 1/6] powerpc: stop exporting irq_map
From: Benjamin Herrenschmidt @ 2011-05-03  1:44 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428200148.8979.66709.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> First step in eliminating irq_map[] table entirely
> 
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  

Ack in principle, needs scrutiny and testing of course :-)

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 0/6] General device tree irq domain infrastructure
From: Benjamin Herrenschmidt @ 2011-05-03  1:43 UTC (permalink / raw)
  To: Grant Likely
  Cc: Michal Simek, Sebastian Andrzej Siewior, x86, linux-kernel,
	Ralf Baechle, hpa, Dirk Brandewie, Thomas Gleixner, linuxppc-dev,
	devicetree-discuss
In-Reply-To: <20110428192227.8979.49181.stgit@ponder>

On Thu, 2011-04-28 at 14:01 -0600, Grant Likely wrote:
> A lot of this series ends up being fixups to powerpc code; but the 4th
> patch is of importance to every architecture using CONFIG_OF (except
> SPARC, which has its own solution).
> 
> This series (finally!) factors out device tree irq domain decoding
> from arch/powerpc and makes it generic for all architectures.  The
> infrastructure is quite simple.  Any interrupt controller can embed
> the of_irq_domain structure and register it with the core code.  After
> that, device nodes referencing interrupts on that device tree node
> will trigger a call to the domain's map function.

This leads to an immediate reaction from me : why "of_irq_domain" ?

The concept of interrupt domains is completely orthogonal to "OF" and
whether you use the device-tree or not.

Having a remapping mechanism allowing to deal with multiple interrupt
domains without playing stupid numbering tricks is generally useful for
architectures, regardless of their adoption of the device-tree.

The irq domain has one and -only one- op that is related to OF which
allows to map a device node to a domain, but that's 'optional' and only
use if you use the OF resolving process. The whole mechanism can be (and
is under some circumstances on ppc) without a device-tree relationship.

We instanciate IRQs within domains manually in some cases, either
because we lack proper DT informations or bcs the IRQs come from the
firmware or as "created" out of the blue (device-tree). A domain pointer
(or NULL for the default domain) is all is needed.

Thus I object to tying this infrastructure generically to "OF" even if
it's just a mater of naming of the domain structure and location of the
code in the kernel tree.

It should basically all go into kernel/irq/domains.c or something like
that.

Cheers,
Ben.

> PowerPC and x86 have been converted to use of_irq_domain.  MIPS and
> Microblaze have it enabled, but nothing actually registers domains
> yet, so a workaround is in place to preserve the current behaviour
> until it is fixed.
> 
> I'd really like to get patches 1-4 merged into 2.6.40.  Please test.
> I'm also running through build testing here, and when it's complete
> I'll push it out to a 'devicetree/irq-domain' branch on
> git://git.secretlab.ca/git/linux-2.6
> 
> It needs testing.  I've booted it on a powerpc board here without any
> apparent regressions, but that isn't a very big sample.  I've also
> build tested on everything I think is affected.
> 
> I'd also like to get it into linux-next.  Ben, if things checkout okay
> over the next few days, would you be okay with me adding it to
> linux-next, say around Wednesday next week?  As for merging, I think
> this should probably go via your powerpc tree since the that's where
> the bulk of the changes are, but I'm open to other suggestions).
> 
> Patches 5 & 6 are follow-on cleanup work to powerpc, but patch 6 is
> RFC only since there is a locking problem that I haven't fixed yet.
> 
> Cheers,
> g.
> 
> ---
> 
> Grant Likely (6):
>       powerpc: stop exporting irq_map
>       powerpc: make irq_{alloc,free}_virt private and remove count argument
>       powerpc: Make struct irq_host semi-private by moving into irqhost.h
>       dt: generalize of_irq_parse_and_map()
>       powerpc: move irq_alloc_descs_at() call into irq_alloc_virt()
>       powerpc: use irq_alloc_desc() to manage irq allocations
> 
> 
>  arch/microblaze/kernel/irq.c                     |    7 -
>  arch/microblaze/kernel/setup.c                   |    2 
>  arch/mips/kernel/prom.c                          |   14 -
>  arch/powerpc/include/asm/irq.h                   |   88 +------
>  arch/powerpc/include/asm/irqhost.h               |   27 ++
>  arch/powerpc/kernel/irq.c                        |  260 ++++++++++++----------
>  arch/powerpc/platforms/512x/mpc5121_ads_cpld.c   |    5 
>  arch/powerpc/platforms/52xx/media5200.c          |    5 
>  arch/powerpc/platforms/52xx/mpc52xx_gpt.c        |    1 
>  arch/powerpc/platforms/52xx/mpc52xx_pic.c        |   80 +------
>  arch/powerpc/platforms/82xx/pq2ads-pci-pic.c     |    5 
>  arch/powerpc/platforms/85xx/socrates_fpga_pic.c  |   26 +-
>  arch/powerpc/platforms/86xx/gef_pic.c            |   10 -
>  arch/powerpc/platforms/8xx/m8xx_setup.c          |    2 
>  arch/powerpc/platforms/cell/axon_msi.c           |   15 +
>  arch/powerpc/platforms/cell/spider-pic.c         |   19 +-
>  arch/powerpc/platforms/embedded6xx/flipper-pic.c |    9 -
>  arch/powerpc/platforms/embedded6xx/hlwd-pic.c    |    9 -
>  arch/powerpc/platforms/embedded6xx/wii.c         |    6 -
>  arch/powerpc/platforms/iseries/irq.c             |   10 -
>  arch/powerpc/platforms/powermac/pic.c            |   12 +
>  arch/powerpc/platforms/pseries/ras.c             |    4 
>  arch/powerpc/platforms/pseries/xics.c            |   14 +
>  arch/powerpc/sysdev/cpm1.c                       |    8 -
>  arch/powerpc/sysdev/cpm2_pic.c                   |   10 -
>  arch/powerpc/sysdev/fsl_msi.c                    |    3 
>  arch/powerpc/sysdev/i8259.c                      |    3 
>  arch/powerpc/sysdev/ipic.c                       |   19 +-
>  arch/powerpc/sysdev/mpc8xx_pic.c                 |   10 -
>  arch/powerpc/sysdev/mpc8xxx_gpio.c               |   13 +
>  arch/powerpc/sysdev/mpic.c                       |   33 +--
>  arch/powerpc/sysdev/mpic_msi.c                   |    3 
>  arch/powerpc/sysdev/mpic_pasemi_msi.c            |    5 
>  arch/powerpc/sysdev/mv64x60_pic.c                |   14 +
>  arch/powerpc/sysdev/qe_lib/qe_ic.c               |    9 -
>  arch/powerpc/sysdev/uic.c                        |   13 +
>  arch/powerpc/sysdev/xilinx_intc.c                |    9 -
>  arch/x86/include/asm/irq_controller.h            |   12 -
>  arch/x86/include/asm/prom.h                      |    1 
>  arch/x86/kernel/devicetree.c                     |   77 +------
>  drivers/of/irq.c                                 |  118 ++++++++++
>  include/linux/of_irq.h                           |   31 +++
>  42 files changed, 504 insertions(+), 517 deletions(-)
>  create mode 100644 arch/powerpc/include/asm/irqhost.h
>  delete mode 100644 arch/x86/include/asm/irq_controller.h

^ permalink raw reply

* Re: [PATCH 1/4] crypto: caam - handle interrupt lines shared across rings
From: Herbert Xu @ 2011-05-02 23:56 UTC (permalink / raw)
  To: Kim Phillips; +Cc: Steve Cornelius, linuxppc-dev, linux-crypto
In-Reply-To: <20110502182727.366857bd.kim.phillips@freescale.com>

On Mon, May 02, 2011 at 06:27:27PM -0500, Kim Phillips wrote:
>
> I don't see them in cryptodev-2.6 - did you forget to push them?

Indeed, they were stuck on my other machine.  They should be on
master now and should show up on the public mirror soon.

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PATCH 1/4] crypto: caam - handle interrupt lines shared across rings
From: Kim Phillips @ 2011-05-02 23:27 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Steve Cornelius, linuxppc-dev, linux-crypto
In-Reply-To: <20110415095049.GA2129@gondor.apana.org.au>

On Fri, 15 Apr 2011 17:50:49 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:

> On Mon, Apr 11, 2011 at 07:15:16PM -0500, Kim Phillips wrote:
> > - add IRQF_SHARED to request_irq flags to support parts such as
> > the p1023 that has one IRQ line per couple of rings.
> > 
> > - resetting a job ring triggers an interrupt, so move request_irq
> > prior to jr_reset to avoid 'got IRQ but nobody cared' messages.
> > 
> > - disable IRQs in h/w to avoid contention between reset and
> > interrupt status
> > 
> > - delete invalid comment - if there were incomplete jobs,
> > module would be in use, preventing an unload.
> > 
> > Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
> > ---
> > this, and the remaining patches in this series, tested on p1023, p3041,
> > p4080, and 32- and 64-bit p5020.
> 
> All four patches applied.  Thanks Kim!

I don't see them in cryptodev-2.6 - did you forget to push them?

Thanks,

Kim

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-02 22:37 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <20110502222716.GB15187@ponder.secretlab.ca>

On Mon, May 2, 2011 at 4:27 PM, Grant Likely <grant.likely@secretlab.ca> wr=
ote:
> On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
>> - add commandline options:
>> =A0 sm501fb.mode:
>> =A0 =A0 Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>> =A0 sm501fb.bpp:
>> =A0 =A0 Specify bit-per-pixel if not specified mode
>>
>> - Add support for encoding display mode information
>> =A0 in the device tree using verbatim EDID block.
>>
>> =A0 If the "edid" entry in the "smi,sm501" node is present,
>> =A0 the driver will build mode database using EDID data
>> =A0 and allow setting the display modes from this database.
>>
>> Signed-off-by: Heiko Schocher <hs@denx.de>
>
> Merged, thanks.

This patch causes the following build warning:

  MODPOST vmlinux.o
WARNING: vmlinux.o(.text+0x1d5572): Section mismatch in reference from
the function sm501fb_init_fb() to the variable
.devinit.data:sm501_default_mode
The function sm501fb_init_fb() references
the variable __devinitdata sm501_default_mode.
This is often because sm501fb_init_fb lacks a __devinitdata
annotation or the annotation of sm501_default_mode is wrong.

WARNING: vmlinux.o(.text+0x1d557a): Section mismatch in reference from
the function sm501fb_init_fb() to the variable
.devinit.data:sm501_default_mode
The function sm501fb_init_fb() references
the variable __devinitdata sm501_default_mode.
This is often because sm501fb_init_fb lacks a __devinitdata
annotation or the annotation of sm501_default_mode is wrong.

I've dropped the __devinitdata declaration in what I committed; can
you investigate and post a fixup patch?

>
> g.
>
>> cc: Wolfram Sang <w.sang@pengutronix.de>
>> cc: Grant Likely <grant.likely@secretlab.ca>
>> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> cc: linux-fbdev@vger.kernel.org
>> cc: devicetree-discuss@ozlabs.org
>> cc: Ben Dooks <ben@simtec.co.uk>
>> cc: Vincent Sanders <vince@simtec.co.uk>
>> cc: Samuel Ortiz <sameo@linux.intel.com>
>> cc: linux-kernel@vger.kernel.org
>> cc: Randy Dunlap <rdunlap@xenotime.net>
>> cc: Wolfgang Denk <wd@denx.de>
>> cc: Paul Mundt <lethal@linux-sh.org>
>> ---
>> - changes since v1:
>> =A0 add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested =
from
>> =A0 Paul Mundt.
>> - changes since v2:
>> =A0 add comments from Randy Dunlap:
>> =A0 - move parameter documentation to Documentation/fb/sm501.txt
>> - changes since v3:
>> =A0 - rebased against v2.6.38-rc2
>> =A0 - split in 3 patches
>> =A0 =A0 - of support patch
>> =A0 =A0 - i/o routine patch
>> =A0 =A0 - edid support patch
>> - changes since v4:
>> =A0 - add "info->pdata =3D &sm501fb_def_pdata;" in sm501fb_probe()
>> =A0 =A0 as Paul Mundt suggested (and I wrongly deleted)
>> =A0 - move kfree(info->edid_data); to patch 3/4
>> =A0 =A0 as edid_data is only allocated in the CONFIG_OF case
>> - changes for v6:
>> =A0 - repost complete patchserie
>> =A0 - rebased against current head
>>
>> =A0Documentation/fb/sm501.txt | =A0 10 +++++++
>> =A0drivers/video/sm501fb.c =A0 =A0| =A0 65 +++++++++++++++++++++++++++++=
+++++++++++---
>> =A02 files changed, 70 insertions(+), 5 deletions(-)
>> =A0create mode 100644 Documentation/fb/sm501.txt
>>
>> diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt
>> new file mode 100644
>> index 0000000..8d17aeb
>> --- /dev/null
>> +++ b/Documentation/fb/sm501.txt
>> @@ -0,0 +1,10 @@
>> +Configuration:
>> +
>> +You can pass the following kernel command line options to sm501 videofr=
amebuffer:
>> +
>> + =A0 =A0 sm501fb.bpp=3D =A0 =A0SM501 Display driver:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Specifiy bits-per-pixel if not=
 specified by 'mode'
>> +
>> + =A0 =A0 sm501fb.mode=3D =A0 SM501 Display driver:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Specify resolution as
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "<xres>x<yres>[-<bpp>][@<refre=
sh>]"
>> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
>> index 5df406c..f31252c 100644
>> --- a/drivers/video/sm501fb.c
>> +++ b/drivers/video/sm501fb.c
>> @@ -41,6 +41,26 @@
>> =A0#include <linux/sm501.h>
>> =A0#include <linux/sm501-regs.h>
>>
>> +#include "edid.h"
>> +
>> +static char *fb_mode =3D "640x480-16@60";
>> +static unsigned long default_bpp =3D 16;
>> +
>> +static struct fb_videomode __devinitdata sm501_default_mode =3D {
>> + =A0 =A0 .refresh =A0 =A0 =A0 =A0=3D 60,
>> + =A0 =A0 .xres =A0 =A0 =A0 =A0 =A0 =3D 640,
>> + =A0 =A0 .yres =A0 =A0 =A0 =A0 =A0 =3D 480,
>> + =A0 =A0 .pixclock =A0 =A0 =A0 =3D 20833,
>> + =A0 =A0 .left_margin =A0 =A0=3D 142,
>> + =A0 =A0 .right_margin =A0 =3D 13,
>> + =A0 =A0 .upper_margin =A0 =3D 21,
>> + =A0 =A0 .lower_margin =A0 =3D 1,
>> + =A0 =A0 .hsync_len =A0 =A0 =A0=3D 69,
>> + =A0 =A0 .vsync_len =A0 =A0 =A0=3D 3,
>> + =A0 =A0 .sync =A0 =A0 =A0 =A0 =A0 =3D FB_SYNC_HOR_HIGH_ACT | FB_SYNC_V=
ERT_HIGH_ACT,
>> + =A0 =A0 .vmode =A0 =A0 =A0 =A0 =A0=3D FB_VMODE_NONINTERLACED
>> +};
>> +
>> =A0#define NR_PALETTE =A0 256
>>
>> =A0enum sm501_controller {
>> @@ -77,6 +97,7 @@ struct sm501fb_info {
>> =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*regs2d; =A0 =A0 =A0 =A0=
/* 2d remapped registers */
>> =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*fbmem; =A0 =A0 =A0 =A0 =
/* remapped framebuffer */
>> =A0 =A0 =A0 size_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fbmem_len; =A0 =
=A0 /* length of remapped region */
>> + =A0 =A0 u8 *edid_data;
>> =A0};
>>
>> =A0/* per-framebuffer private data */
>> @@ -1725,9 +1746,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
>> =A0 =A0 =A0 fb->var.vmode =A0 =A0 =A0 =A0 =A0 =3D FB_VMODE_NONINTERLACED=
;
>> =A0 =A0 =A0 fb->var.bits_per_pixel =A0=3D 16;
>>
>> + =A0 =A0 if (info->edid_data) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Now build modedb from EDID =
*/
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb_edid_to_monspecs(info->edid=
_data, &fb->monspecs);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb_videomode_to_modelist(fb->m=
onspecs.modedb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0fb->monspecs.modedb_len,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0&fb->modelist);
>> + =A0 =A0 }
>> +
>> =A0 =A0 =A0 if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0)=
 {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* TODO read the mode from the current displ=
ay */
>> -
>> =A0 =A0 =A0 } else {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (pd->def_mode) {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info->dev, "using s=
upplied mode\n");
>> @@ -1737,12 +1765,34 @@ static int sm501fb_init_fb(struct fb_info *fb,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb->var.xres_virtual =3D fb-=
>var.xres;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fb->var.yres_virtual =3D fb-=
>var.yres;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_find_mode(&fb->var,=
 fb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (info->edid_data)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_fin=
d_mode(&fb->var, fb, fb_mode,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 fb->monspecs.modedb,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 fb->monspecs.modedb_len,
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 &sm501_default_mode, default_bpp);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D fb_fin=
d_mode(&fb->var, fb,
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0NULL, NULL, 0, NULL, 8);
>>
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ret =3D=3D 0 || ret =3D=3D=
 4) {
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(info->=
dev,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "failed to get initial mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 switch (ret) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 1:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode specified in "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 "@mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 2:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode specified in "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "@mode with ignored refresh rate\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 3:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode default "
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 "mode\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 4:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "using mode from list\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 default:
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "ret =3D %d\n", ret);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_info(info-=
>dev, "failed to find mode\n");
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINV=
AL;
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>> @@ -2157,6 +2207,11 @@ static void __exit sm501fb_cleanup(void)
>> =A0module_init(sm501fb_init);
>> =A0module_exit(sm501fb_cleanup);
>>
>> +module_param_named(mode, fb_mode, charp, 0);
>> +MODULE_PARM_DESC(mode,
>> + =A0 =A0 "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "=
);
>> +module_param_named(bpp, default_bpp, ulong, 0);
>> +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
>> =A0MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
>> =A0MODULE_DESCRIPTION("SM501 Framebuffer driver");
>> =A0MODULE_LICENSE("GPL v2");
>> --
>> 1.7.4
>>
>



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

^ permalink raw reply

* Re: [PATCH v6 6/6] powerpc, tqm5200: update tqm5200_defconfig to fit for charon board.
From: Grant Likely @ 2011-05-02 22:31 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, Heiko Schocher,
	linuxppc-dev, Wolfgang Denk
In-Reply-To: <20110322091027.GC2134@pengutronix.de>

On Tue, Mar 22, 2011 at 10:10:27AM +0100, Wolfram Sang wrote:
> >     As this board is tqm5200 based, added necessary changes
> >     to the tqm5200_defconfig. In previous patchserie I added
> >     the changes to mpc5200_defconfig, as Wolfram Sang mentioned,
> >     but as tqm5200_defconfig is in mainline, and the board is
> >     tqm5200 based, I think, thats the appropriate place, as
> 
> I'd think the perfect solution would have been to merge the
> tqm-defconfig into the mpc5200-defconfig entirely and get rid of it.
> That being said, I don't think this issue is big enough to block this
> series, so fine enough with me.

Merged, thanks.

g.

^ permalink raw reply

* Re: [PATCH v6 4/6] video, sm501: add OF binding to support SM501
From: Grant Likely @ 2011-05-02 22:28 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-5-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:30AM +0100, Heiko Schocher wrote:
> - add binding to OF, compatible name "smi,sm501"
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>
> Acked-by: Samuel Ortiz <sameo@linux.intel.com>

Merged, thanks.

g.

> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> - changes since v2:
>   add comments from Randy Dunlap:
>   - move parameter documentation to Documentation/fb/sm501.txt
> - changes since v3:
>   - rebased against v2.6.38-rc2
>   - split in 3 patches
>     - of support patch
>       - get rid of "#if defined(CONFIG_PPC_MPC52xx)" usage
>         hide this in DTS, as Paul suggested.
>     - i/o routine patch
>     - edid support patch
> - changes since v4
>   replace remaining CONFIG_PPC_MPC52xx with CONFIG_OF, as
>   it is no longer MPC52xx only.
> - changes since v5
>   free edid_data after its usage, as it is no longer needed,
>   suggested from Paul Mundt. Also fall back to default if
>   kmemdup(edid_data) fails.
> - changes for v6:
>   - repost complete patchserie
>   - rebased against current head
> 
>  Documentation/powerpc/dts-bindings/sm501.txt |   34 +++++++++++++++++++++++++
>  drivers/mfd/sm501.c                          |    8 +++++-
>  drivers/video/sm501fb.c                      |   35 +++++++++++++++++++++++++-
>  3 files changed, 75 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/powerpc/dts-bindings/sm501.txt
> 
> diff --git a/Documentation/powerpc/dts-bindings/sm501.txt b/Documentation/powerpc/dts-bindings/sm501.txt
> new file mode 100644
> index 0000000..7d319fb
> --- /dev/null
> +++ b/Documentation/powerpc/dts-bindings/sm501.txt
> @@ -0,0 +1,34 @@
> +* SM SM501
> +
> +The SM SM501 is a LCD controller, with proper hardware, it can also
> +drive DVI monitors.
> +
> +Required properties:
> +- compatible : should be "smi,sm501".
> +- reg : contain two entries:
> +    - First entry: System Configuration register
> +    - Second entry: IO space (Display Controller register)
> +- interrupts : SMI interrupt to the cpu should be described here.
> +- interrupt-parent : the phandle for the interrupt controller that
> +  services interrupts for this device.
> +
> +Optional properties:
> +- mode : select a video mode:
> +    <xres>x<yres>[-<bpp>][@<refresh>]
> +- edid : verbatim EDID data block describing attached display.
> +  Data from the detailed timing descriptor will be used to
> +  program the display controller.
> +- little-endian: availiable on big endian systems, to
> +  set different foreign endian.
> +- big-endian: availiable on little endian systems, to
> +  set different foreign endian.
> +
> +Example for MPC5200:
> +	display@1,0 {
> +		compatible = "smi,sm501";
> +		reg = <1 0x00000000 0x00800000
> +		       1 0x03e00000 0x00200000>;
> +		interrupts = <1 1 3>;
> +		mode = "640x480-32@60";
> +		edid = [edid-data];
> +	};
> diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
> index 558d5f3..574f696 100644
> --- a/drivers/mfd/sm501.c
> +++ b/drivers/mfd/sm501.c
> @@ -1377,7 +1377,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
>  			sm501_register_gpio(sm);
>  	}
>  
> -	if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
> +	if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) {
>  		if (!sm501_gpio_isregistered(sm))
>  			dev_err(sm->dev, "no gpio available for i2c gpio.\n");
>  		else
> @@ -1735,10 +1735,16 @@ static struct pci_driver sm501_pci_driver = {
>  
>  MODULE_ALIAS("platform:sm501");
>  
> +static struct of_device_id __devinitdata of_sm501_match_tbl[] = {
> +	{ .compatible = "smi,sm501", },
> +	{ /* end */ }
> +};
> +
>  static struct platform_driver sm501_plat_driver = {
>  	.driver		= {
>  		.name	= "sm501",
>  		.owner	= THIS_MODULE,
> +		.of_match_table = of_sm501_match_tbl,
>  	},
>  	.probe		= sm501_plat_probe,
>  	.remove		= sm501_plat_remove,
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index f31252c..f275385 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -1729,6 +1729,15 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
>  		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
>  
> +#if defined(CONFIG_OF)
> +#ifdef __BIG_ENDIAN
> +	if (of_get_property(info->dev->parent->of_node, "little-endian", NULL))
> +		fb->flags |= FBINFO_FOREIGN_ENDIAN;
> +#else
> +	if (of_get_property(info->dev->parent->of_node, "big-endian", NULL))
> +		fb->flags |= FBINFO_FOREIGN_ENDIAN;
> +#endif
> +#endif
>  	/* fixed data */
>  
>  	fb->fix.type		= FB_TYPE_PACKED_PIXELS;
> @@ -1933,8 +1942,32 @@ static int __devinit sm501fb_probe(struct platform_device *pdev)
>  	}
>  
>  	if (info->pdata == NULL) {
> -		dev_info(dev, "using default configuration data\n");
> +		int found = 0;
> +#if defined(CONFIG_OF)
> +		struct device_node *np = pdev->dev.parent->of_node;
> +		const u8 *prop;
> +		const char *cp;
> +		int len;
> +
>  		info->pdata = &sm501fb_def_pdata;
> +		if (np) {
> +			/* Get EDID */
> +			cp = of_get_property(np, "mode", &len);
> +			if (cp)
> +				strcpy(fb_mode, cp);
> +			prop = of_get_property(np, "edid", &len);
> +			if (prop && len == EDID_LENGTH) {
> +				info->edid_data = kmemdup(prop, EDID_LENGTH,
> +							  GFP_KERNEL);
> +				if (info->edid_data)
> +					found = 1;
> +			}
> +		}
> +#endif
> +		if (!found) {
> +			dev_info(dev, "using default configuration data\n");
> +			info->pdata = &sm501fb_def_pdata;
> +		}
>  	}
>  
>  	/* probe for the presence of each panel */
> -- 
> 1.7.4
> 

^ permalink raw reply

* Re: [PATCH v6 3/6] video, sm501: add edid and commandline support
From: Grant Likely @ 2011-05-02 22:27 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-4-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:29AM +0100, Heiko Schocher wrote:
> - add commandline options:
>   sm501fb.mode:
>     Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>   sm501fb.bpp:
>     Specify bit-per-pixel if not specified mode
> 
> - Add support for encoding display mode information
>   in the device tree using verbatim EDID block.
> 
>   If the "edid" entry in the "smi,sm501" node is present,
>   the driver will build mode database using EDID data
>   and allow setting the display modes from this database.
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>

Merged, thanks.

g.

> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> - changes since v2:
>   add comments from Randy Dunlap:
>   - move parameter documentation to Documentation/fb/sm501.txt
> - changes since v3:
>   - rebased against v2.6.38-rc2
>   - split in 3 patches
>     - of support patch
>     - i/o routine patch
>     - edid support patch
> - changes since v4:
>   - add "info->pdata = &sm501fb_def_pdata;" in sm501fb_probe()
>     as Paul Mundt suggested (and I wrongly deleted)
>   - move kfree(info->edid_data); to patch 3/4
>     as edid_data is only allocated in the CONFIG_OF case
> - changes for v6:
>   - repost complete patchserie
>   - rebased against current head
> 
>  Documentation/fb/sm501.txt |   10 +++++++
>  drivers/video/sm501fb.c    |   65 ++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 70 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/fb/sm501.txt
> 
> diff --git a/Documentation/fb/sm501.txt b/Documentation/fb/sm501.txt
> new file mode 100644
> index 0000000..8d17aeb
> --- /dev/null
> +++ b/Documentation/fb/sm501.txt
> @@ -0,0 +1,10 @@
> +Configuration:
> +
> +You can pass the following kernel command line options to sm501 videoframebuffer:
> +
> +	sm501fb.bpp=	SM501 Display driver:
> +			Specifiy bits-per-pixel if not specified by 'mode'
> +
> +	sm501fb.mode=	SM501 Display driver:
> +			Specify resolution as
> +			"<xres>x<yres>[-<bpp>][@<refresh>]"
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index 5df406c..f31252c 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -41,6 +41,26 @@
>  #include <linux/sm501.h>
>  #include <linux/sm501-regs.h>
>  
> +#include "edid.h"
> +
> +static char *fb_mode = "640x480-16@60";
> +static unsigned long default_bpp = 16;
> +
> +static struct fb_videomode __devinitdata sm501_default_mode = {
> +	.refresh	= 60,
> +	.xres		= 640,
> +	.yres		= 480,
> +	.pixclock	= 20833,
> +	.left_margin	= 142,
> +	.right_margin	= 13,
> +	.upper_margin	= 21,
> +	.lower_margin	= 1,
> +	.hsync_len	= 69,
> +	.vsync_len	= 3,
> +	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> +	.vmode		= FB_VMODE_NONINTERLACED
> +};
> +
>  #define NR_PALETTE	256
>  
>  enum sm501_controller {
> @@ -77,6 +97,7 @@ struct sm501fb_info {
>  	void __iomem		*regs2d;	/* 2d remapped registers */
>  	void __iomem		*fbmem;		/* remapped framebuffer */
>  	size_t			 fbmem_len;	/* length of remapped region */
> +	u8 *edid_data;
>  };
>  
>  /* per-framebuffer private data */
> @@ -1725,9 +1746,16 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  	fb->var.vmode		= FB_VMODE_NONINTERLACED;
>  	fb->var.bits_per_pixel  = 16;
>  
> +	if (info->edid_data) {
> +			/* Now build modedb from EDID */
> +			fb_edid_to_monspecs(info->edid_data, &fb->monspecs);
> +			fb_videomode_to_modelist(fb->monspecs.modedb,
> +						 fb->monspecs.modedb_len,
> +						 &fb->modelist);
> +	}
> +
>  	if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) {
>  		/* TODO read the mode from the current display */
> -
>  	} else {
>  		if (pd->def_mode) {
>  			dev_info(info->dev, "using supplied mode\n");
> @@ -1737,12 +1765,34 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  			fb->var.xres_virtual = fb->var.xres;
>  			fb->var.yres_virtual = fb->var.yres;
>  		} else {
> -			ret = fb_find_mode(&fb->var, fb,
> +			if (info->edid_data)
> +				ret = fb_find_mode(&fb->var, fb, fb_mode,
> +					fb->monspecs.modedb,
> +					fb->monspecs.modedb_len,
> +					&sm501_default_mode, default_bpp);
> +			else
> +				ret = fb_find_mode(&fb->var, fb,
>  					   NULL, NULL, 0, NULL, 8);
>  
> -			if (ret == 0 || ret == 4) {
> -				dev_err(info->dev,
> -					"failed to get initial mode\n");
> +			switch (ret) {
> +			case 1:
> +				dev_info(info->dev, "using mode specified in "
> +						"@mode\n");
> +				break;
> +			case 2:
> +				dev_info(info->dev, "using mode specified in "
> +					"@mode with ignored refresh rate\n");
> +				break;
> +			case 3:
> +				dev_info(info->dev, "using mode default "
> +					"mode\n");
> +				break;
> +			case 4:
> +				dev_info(info->dev, "using mode from list\n");
> +				break;
> +			default:
> +				dev_info(info->dev, "ret = %d\n", ret);
> +				dev_info(info->dev, "failed to find mode\n");
>  				return -EINVAL;
>  			}
>  		}
> @@ -2157,6 +2207,11 @@ static void __exit sm501fb_cleanup(void)
>  module_init(sm501fb_init);
>  module_exit(sm501fb_cleanup);
>  
> +module_param_named(mode, fb_mode, charp, 0);
> +MODULE_PARM_DESC(mode,
> +	"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
> +module_param_named(bpp, default_bpp, ulong, 0);
> +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
>  MODULE_AUTHOR("Ben Dooks, Vincent Sanders");
>  MODULE_DESCRIPTION("SM501 Framebuffer driver");
>  MODULE_LICENSE("GPL v2");
> -- 
> 1.7.4
> 

^ permalink raw reply

* Re: [PATCH v6 2/6] video, sm501: add I/O functions for use on powerpc
From: Grant Likely @ 2011-05-02 22:24 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-3-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:28AM +0100, Heiko Schocher wrote:
> - add read/write functions for using this driver
>   also on powerpc plattforms
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>
> Acked-by: Samuel Ortiz <sameo@linux.intel.com>

Merged, thanks.

g.

> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> - changes since v2:
>   add comments from Randy Dunlap:
>   - move parameter documentation to Documentation/fb/sm501.txt
> - changes since v3:
>   - rebased against v2.6.38-rc2
>   - split in 3 patches
>     - of support patch
>     - i/o routine patch
>       - use ioread/write32{be} accessors instead of
>         __do_readl/__do_writel{_be}
>     - edid support patch
> - changes for v6:
>   - repost complete patchserie
>   - rebased against current head
> 
>  drivers/mfd/sm501.c     |  125 +++++++++++++++++-----------------
>  drivers/video/sm501fb.c |  172 ++++++++++++++++++++++++----------------------
>  include/linux/sm501.h   |    8 ++
>  3 files changed, 161 insertions(+), 144 deletions(-)
> 
> diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
> index 5de3a76..558d5f3 100644
> --- a/drivers/mfd/sm501.c
> +++ b/drivers/mfd/sm501.c
> @@ -133,10 +133,10 @@ static unsigned long decode_div(unsigned long pll2, unsigned long val,
>  
>  static void sm501_dump_clk(struct sm501_devdata *sm)
>  {
> -	unsigned long misct = readl(sm->regs + SM501_MISC_TIMING);
> -	unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
> -	unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
> -	unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL);
> +	unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING);
> +	unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK);
> +	unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK);
> +	unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
>  	unsigned long sdclk0, sdclk1;
>  	unsigned long pll2 = 0;
>  
> @@ -193,29 +193,29 @@ static void sm501_dump_regs(struct sm501_devdata *sm)
>  	void __iomem *regs = sm->regs;
>  
>  	dev_info(sm->dev, "System Control   %08x\n",
> -			readl(regs + SM501_SYSTEM_CONTROL));
> +			smc501_readl(regs + SM501_SYSTEM_CONTROL));
>  	dev_info(sm->dev, "Misc Control     %08x\n",
> -			readl(regs + SM501_MISC_CONTROL));
> +			smc501_readl(regs + SM501_MISC_CONTROL));
>  	dev_info(sm->dev, "GPIO Control Low %08x\n",
> -			readl(regs + SM501_GPIO31_0_CONTROL));
> +			smc501_readl(regs + SM501_GPIO31_0_CONTROL));
>  	dev_info(sm->dev, "GPIO Control Hi  %08x\n",
> -			readl(regs + SM501_GPIO63_32_CONTROL));
> +			smc501_readl(regs + SM501_GPIO63_32_CONTROL));
>  	dev_info(sm->dev, "DRAM Control     %08x\n",
> -			readl(regs + SM501_DRAM_CONTROL));
> +			smc501_readl(regs + SM501_DRAM_CONTROL));
>  	dev_info(sm->dev, "Arbitration Ctrl %08x\n",
> -			readl(regs + SM501_ARBTRTN_CONTROL));
> +			smc501_readl(regs + SM501_ARBTRTN_CONTROL));
>  	dev_info(sm->dev, "Misc Timing      %08x\n",
> -			readl(regs + SM501_MISC_TIMING));
> +			smc501_readl(regs + SM501_MISC_TIMING));
>  }
>  
>  static void sm501_dump_gate(struct sm501_devdata *sm)
>  {
>  	dev_info(sm->dev, "CurrentGate      %08x\n",
> -			readl(sm->regs + SM501_CURRENT_GATE));
> +			smc501_readl(sm->regs + SM501_CURRENT_GATE));
>  	dev_info(sm->dev, "CurrentClock     %08x\n",
> -			readl(sm->regs + SM501_CURRENT_CLOCK));
> +			smc501_readl(sm->regs + SM501_CURRENT_CLOCK));
>  	dev_info(sm->dev, "PowerModeControl %08x\n",
> -			readl(sm->regs + SM501_POWER_MODE_CONTROL));
> +			smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL));
>  }
>  
>  #else
> @@ -231,7 +231,7 @@ static inline void sm501_dump_clk(struct sm501_devdata *sm) { }
>  
>  static void sm501_sync_regs(struct sm501_devdata *sm)
>  {
> -	readl(sm->regs);
> +	smc501_readl(sm->regs);
>  }
>  
>  static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay)
> @@ -261,11 +261,11 @@ int sm501_misc_control(struct device *dev,
>  
>  	spin_lock_irqsave(&sm->reg_lock, save);
>  
> -	misc = readl(sm->regs + SM501_MISC_CONTROL);
> +	misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
>  	to = (misc & ~clear) | set;
>  
>  	if (to != misc) {
> -		writel(to, sm->regs + SM501_MISC_CONTROL);
> +		smc501_writel(to, sm->regs + SM501_MISC_CONTROL);
>  		sm501_sync_regs(sm);
>  
>  		dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc);
> @@ -294,11 +294,11 @@ unsigned long sm501_modify_reg(struct device *dev,
>  
>  	spin_lock_irqsave(&sm->reg_lock, save);
>  
> -	data = readl(sm->regs + reg);
> +	data = smc501_readl(sm->regs + reg);
>  	data |= set;
>  	data &= ~clear;
>  
> -	writel(data, sm->regs + reg);
> +	smc501_writel(data, sm->regs + reg);
>  	sm501_sync_regs(sm);
>  
>  	spin_unlock_irqrestore(&sm->reg_lock, save);
> @@ -322,9 +322,9 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
>  
>  	mutex_lock(&sm->clock_lock);
>  
> -	mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
> -	gate = readl(sm->regs + SM501_CURRENT_GATE);
> -	clock = readl(sm->regs + SM501_CURRENT_CLOCK);
> +	mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
> +	gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
> +	clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
>  
>  	mode &= 3;		/* get current power mode */
>  
> @@ -356,14 +356,14 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
>  
>  	switch (mode) {
>  	case 1:
> -		writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
> -		writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
> +		smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
> +		smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
>  		mode = 0;
>  		break;
>  	case 2:
>  	case 0:
> -		writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
> -		writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
> +		smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
> +		smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
>  		mode = 1;
>  		break;
>  
> @@ -372,7 +372,7 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
>  		goto already;
>  	}
>  
> -	writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
> +	smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
>  	sm501_sync_regs(sm);
>  
>  	dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n",
> @@ -519,9 +519,9 @@ unsigned long sm501_set_clock(struct device *dev,
>  			      unsigned long req_freq)
>  {
>  	struct sm501_devdata *sm = dev_get_drvdata(dev);
> -	unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
> -	unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE);
> -	unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK);
> +	unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
> +	unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
> +	unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
>  	unsigned char reg;
>  	unsigned int pll_reg = 0;
>  	unsigned long sm501_freq; /* the actual frequency achieved */
> @@ -592,9 +592,9 @@ unsigned long sm501_set_clock(struct device *dev,
>  
>  	mutex_lock(&sm->clock_lock);
>  
> -	mode = readl(sm->regs + SM501_POWER_MODE_CONTROL);
> -	gate = readl(sm->regs + SM501_CURRENT_GATE);
> -	clock = readl(sm->regs + SM501_CURRENT_CLOCK);
> +	mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL);
> +	gate = smc501_readl(sm->regs + SM501_CURRENT_GATE);
> +	clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
>  
>  	clock = clock & ~(0xFF << clksrc);
>  	clock |= reg<<clksrc;
> @@ -603,14 +603,14 @@ unsigned long sm501_set_clock(struct device *dev,
>  
>  	switch (mode) {
>  	case 1:
> -		writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
> -		writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
> +		smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE);
> +		smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK);
>  		mode = 0;
>  		break;
>  	case 2:
>  	case 0:
> -		writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
> -		writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
> +		smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE);
> +		smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK);
>  		mode = 1;
>  		break;
>  
> @@ -619,10 +619,11 @@ unsigned long sm501_set_clock(struct device *dev,
>  		return -1;
>  	}
>  
> -	writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
> +	smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
>  
>  	if (pll_reg)
> -		writel(pll_reg, sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL);
> +		smc501_writel(pll_reg,
> +				sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL);
>  
>  	sm501_sync_regs(sm);
>  
> @@ -902,7 +903,7 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
>  	struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip);
>  	unsigned long result;
>  
> -	result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
> +	result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW);
>  	result >>= offset;
>  
>  	return result & 1UL;
> @@ -915,13 +916,13 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
>  
>  	/* check and modify if this pin is not set as gpio. */
>  
> -	if (readl(smchip->control) & bit) {
> +	if (smc501_readl(smchip->control) & bit) {
>  		dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev,
>  			 "changing mode of gpio, bit %08lx\n", bit);
>  
> -		ctrl = readl(smchip->control);
> +		ctrl = smc501_readl(smchip->control);
>  		ctrl &= ~bit;
> -		writel(ctrl, smchip->control);
> +		smc501_writel(ctrl, smchip->control);
>  
>  		sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio));
>  	}
> @@ -942,10 +943,10 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>  
>  	spin_lock_irqsave(&smgpio->lock, save);
>  
> -	val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
> +	val = smc501_readl(regs + SM501_GPIO_DATA_LOW) & ~bit;
>  	if (value)
>  		val |= bit;
> -	writel(val, regs);
> +	smc501_writel(val, regs);
>  
>  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
>  	sm501_gpio_ensure_gpio(smchip, bit);
> @@ -967,8 +968,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
>  
>  	spin_lock_irqsave(&smgpio->lock, save);
>  
> -	ddr = readl(regs + SM501_GPIO_DDR_LOW);
> -	writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
> +	ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
> +	smc501_writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
>  
>  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
>  	sm501_gpio_ensure_gpio(smchip, bit);
> @@ -994,18 +995,18 @@ static int sm501_gpio_output(struct gpio_chip *chip,
>  
>  	spin_lock_irqsave(&smgpio->lock, save);
>  
> -	val = readl(regs + SM501_GPIO_DATA_LOW);
> +	val = smc501_readl(regs + SM501_GPIO_DATA_LOW);
>  	if (value)
>  		val |= bit;
>  	else
>  		val &= ~bit;
> -	writel(val, regs);
> +	smc501_writel(val, regs);
>  
> -	ddr = readl(regs + SM501_GPIO_DDR_LOW);
> -	writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
> +	ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW);
> +	smc501_writel(ddr | bit, regs + SM501_GPIO_DDR_LOW);
>  
>  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
> -	writel(val, regs + SM501_GPIO_DATA_LOW);
> +	smc501_writel(val, regs + SM501_GPIO_DATA_LOW);
>  
>  	sm501_sync_regs(sm501_gpio_to_dev(smgpio));
>  	spin_unlock_irqrestore(&smgpio->lock, save);
> @@ -1231,7 +1232,7 @@ static ssize_t sm501_dbg_regs(struct device *dev,
>  
>  	for (reg = 0x00; reg < 0x70; reg += 4) {
>  		ret = sprintf(ptr, "%08x = %08x\n",
> -			      reg, readl(sm->regs + reg));
> +			      reg, smc501_readl(sm->regs + reg));
>  		ptr += ret;
>  	}
>  
> @@ -1255,10 +1256,10 @@ static inline void sm501_init_reg(struct sm501_devdata *sm,
>  {
>  	unsigned long tmp;
>  
> -	tmp = readl(sm->regs + reg);
> +	tmp = smc501_readl(sm->regs + reg);
>  	tmp &= ~r->mask;
>  	tmp |= r->set;
> -	writel(tmp, sm->regs + reg);
> +	smc501_writel(tmp, sm->regs + reg);
>  }
>  
>  /* sm501_init_regs
> @@ -1299,7 +1300,7 @@ static void sm501_init_regs(struct sm501_devdata *sm,
>  
>  static int sm501_check_clocks(struct sm501_devdata *sm)
>  {
> -	unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK);
> +	unsigned long pwrmode = smc501_readl(sm->regs + SM501_CURRENT_CLOCK);
>  	unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC);
>  	unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC);
>  
> @@ -1334,7 +1335,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
>  
>  	INIT_LIST_HEAD(&sm->devices);
>  
> -	devid = readl(sm->regs + SM501_DEVICEID);
> +	devid = smc501_readl(sm->regs + SM501_DEVICEID);
>  
>  	if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) {
>  		dev_err(sm->dev, "incorrect device id %08lx\n", devid);
> @@ -1342,9 +1343,9 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm)
>  	}
>  
>  	/* disable irqs */
> -	writel(0, sm->regs + SM501_IRQ_MASK);
> +	smc501_writel(0, sm->regs + SM501_IRQ_MASK);
>  
> -	dramctrl = readl(sm->regs + SM501_DRAM_CONTROL);
> +	dramctrl = smc501_readl(sm->regs + SM501_DRAM_CONTROL);
>  	mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7];
>  
>  	dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n",
> @@ -1489,7 +1490,7 @@ static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state)
>  	struct sm501_devdata *sm = platform_get_drvdata(pdev);
>  
>  	sm->in_suspend = 1;
> -	sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL);
> +	sm->pm_misc = smc501_readl(sm->regs + SM501_MISC_CONTROL);
>  
>  	sm501_dump_regs(sm);
>  
> @@ -1513,9 +1514,9 @@ static int sm501_plat_resume(struct platform_device *pdev)
>  
>  	/* check to see if we are in the same state as when suspended */
>  
> -	if (readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
> +	if (smc501_readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) {
>  		dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n");
> -		writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
> +		smc501_writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL);
>  
>  		/* our suspend causes the controller state to change,
>  		 * either by something attempting setup, power loss,
> diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
> index bcb44a5..5df406c 100644
> --- a/drivers/video/sm501fb.c
> +++ b/drivers/video/sm501fb.c
> @@ -117,7 +117,7 @@ static inline int v_total(struct fb_var_screeninfo *var)
>  
>  static inline void sm501fb_sync_regs(struct sm501fb_info *info)
>  {
> -	readl(info->regs);
> +	smc501_readl(info->regs);
>  }
>  
>  /* sm501_alloc_mem
> @@ -262,7 +262,7 @@ static void sm501fb_setup_gamma(struct sm501fb_info *fbi,
>  
>  	/* set gamma values */
>  	for (offset = 0; offset < 256 * 4; offset += 4) {
> -		writel(value, fbi->regs + palette + offset);
> +		smc501_writel(value, fbi->regs + palette + offset);
>  		value += 0x010101; 	/* Advance RGB by 1,1,1.*/
>  	}
>  }
> @@ -476,7 +476,8 @@ static int sm501fb_set_par_common(struct fb_info *info,
>  
>  	/* set start of framebuffer to the screen */
>  
> -	writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr);
> +	smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP,
> +			fbi->regs + head_addr);
>  
>  	/* program CRT clock  */
>  
> @@ -519,7 +520,7 @@ static void sm501fb_set_par_geometry(struct fb_info *info,
>  	reg = info->fix.line_length;
>  	reg |= ((var->xres * var->bits_per_pixel)/8) << 16;
>  
> -	writel(reg, fbi->regs + (par->head == HEAD_CRT ?
> +	smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ?
>  		    SM501_DC_CRT_FB_OFFSET :  SM501_DC_PANEL_FB_OFFSET));
>  
>  	/* program horizontal total */
> @@ -527,27 +528,27 @@ static void sm501fb_set_par_geometry(struct fb_info *info,
>  	reg  = (h_total(var) - 1) << 16;
>  	reg |= (var->xres - 1);
>  
> -	writel(reg, base + SM501_OFF_DC_H_TOT);
> +	smc501_writel(reg, base + SM501_OFF_DC_H_TOT);
>  
>  	/* program horizontal sync */
>  
>  	reg  = var->hsync_len << 16;
>  	reg |= var->xres + var->right_margin - 1;
>  
> -	writel(reg, base + SM501_OFF_DC_H_SYNC);
> +	smc501_writel(reg, base + SM501_OFF_DC_H_SYNC);
>  
>  	/* program vertical total */
>  
>  	reg  = (v_total(var) - 1) << 16;
>  	reg |= (var->yres - 1);
>  
> -	writel(reg, base + SM501_OFF_DC_V_TOT);
> +	smc501_writel(reg, base + SM501_OFF_DC_V_TOT);
>  
>  	/* program vertical sync */
>  	reg  = var->vsync_len << 16;
>  	reg |= var->yres + var->lower_margin - 1;
>  
> -	writel(reg, base + SM501_OFF_DC_V_SYNC);
> +	smc501_writel(reg, base + SM501_OFF_DC_V_SYNC);
>  }
>  
>  /* sm501fb_pan_crt
> @@ -566,15 +567,15 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var,
>  
>  	xoffs = var->xoffset * bytes_pixel;
>  
> -	reg = readl(fbi->regs + SM501_DC_CRT_CONTROL);
> +	reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
>  
>  	reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK;
>  	reg |= ((xoffs & 15) / bytes_pixel) << 4;
> -	writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
> +	smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL);
>  
>  	reg = (par->screen.sm_addr + xoffs +
>  	       var->yoffset * info->fix.line_length);
> -	writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
> +	smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR);
>  
>  	sm501fb_sync_regs(fbi);
>  	return 0;
> @@ -593,10 +594,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var,
>  	unsigned long reg;
>  
>  	reg = var->xoffset | (var->xres_virtual << 16);
> -	writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
> +	smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH);
>  
>  	reg = var->yoffset | (var->yres_virtual << 16);
> -	writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
> +	smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT);
>  
>  	sm501fb_sync_regs(fbi);
>  	return 0;
> @@ -622,7 +623,7 @@ static int sm501fb_set_par_crt(struct fb_info *info)
>  	/* enable CRT DAC - note 0 is on!*/
>  	sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER);
>  
> -	control = readl(fbi->regs + SM501_DC_CRT_CONTROL);
> +	control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
>  
>  	control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK |
>  		    SM501_DC_CRT_CONTROL_GAMMA |
> @@ -684,7 +685,7 @@ static int sm501fb_set_par_crt(struct fb_info *info)
>   out_update:
>  	dev_dbg(fbi->dev, "new control is %08lx\n", control);
>  
> -	writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
> +	smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL);
>  	sm501fb_sync_regs(fbi);
>  
>  	return 0;
> @@ -696,18 +697,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
>  	void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL;
>  	struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl;
>  
> -	control = readl(ctrl_reg);
> +	control = smc501_readl(ctrl_reg);
>  
>  	if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) {
>  		/* enable panel power */
>  
>  		control |= SM501_DC_PANEL_CONTROL_VDD;	/* FPVDDEN */
> -		writel(control, ctrl_reg);
> +		smc501_writel(control, ctrl_reg);
>  		sm501fb_sync_regs(fbi);
>  		mdelay(10);
>  
>  		control |= SM501_DC_PANEL_CONTROL_DATA;	/* DATA */
> -		writel(control, ctrl_reg);
> +		smc501_writel(control, ctrl_reg);
>  		sm501fb_sync_regs(fbi);
>  		mdelay(10);
>  
> @@ -719,7 +720,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
>  			else
>  				control |= SM501_DC_PANEL_CONTROL_BIAS;
>  
> -			writel(control, ctrl_reg);
> +			smc501_writel(control, ctrl_reg);
>  			sm501fb_sync_regs(fbi);
>  			mdelay(10);
>  		}
> @@ -730,7 +731,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
>  			else
>  				control |= SM501_DC_PANEL_CONTROL_FPEN;
>  
> -			writel(control, ctrl_reg);
> +			smc501_writel(control, ctrl_reg);
>  			sm501fb_sync_regs(fbi);
>  			mdelay(10);
>  		}
> @@ -742,7 +743,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
>  			else
>  				control &= ~SM501_DC_PANEL_CONTROL_FPEN;
>  
> -			writel(control, ctrl_reg);
> +			smc501_writel(control, ctrl_reg);
>  			sm501fb_sync_regs(fbi);
>  			mdelay(10);
>  		}
> @@ -753,18 +754,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to)
>  			else
>  				control &= ~SM501_DC_PANEL_CONTROL_BIAS;
>  
> -			writel(control, ctrl_reg);
> +			smc501_writel(control, ctrl_reg);
>  			sm501fb_sync_regs(fbi);
>  			mdelay(10);
>  		}
>  
>  		control &= ~SM501_DC_PANEL_CONTROL_DATA;
> -		writel(control, ctrl_reg);
> +		smc501_writel(control, ctrl_reg);
>  		sm501fb_sync_regs(fbi);
>  		mdelay(10);
>  
>  		control &= ~SM501_DC_PANEL_CONTROL_VDD;
> -		writel(control, ctrl_reg);
> +		smc501_writel(control, ctrl_reg);
>  		sm501fb_sync_regs(fbi);
>  		mdelay(10);
>  	}
> @@ -799,7 +800,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
>  
>  	/* update control register */
>  
> -	control = readl(fbi->regs + SM501_DC_PANEL_CONTROL);
> +	control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL);
>  	control &= (SM501_DC_PANEL_CONTROL_GAMMA |
>  		    SM501_DC_PANEL_CONTROL_VDD  |
>  		    SM501_DC_PANEL_CONTROL_DATA |
> @@ -833,16 +834,16 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
>  		BUG();
>  	}
>  
> -	writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
> +	smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL);
>  
>  	/* panel plane top left and bottom right location */
>  
> -	writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
> +	smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC);
>  
>  	reg  = var->xres - 1;
>  	reg |= (var->yres - 1) << 16;
>  
> -	writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
> +	smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC);
>  
>  	/* program panel control register */
>  
> @@ -855,7 +856,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
>  	if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
>  		control |= SM501_DC_PANEL_CONTROL_VSP;
>  
> -	writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
> +	smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
>  	sm501fb_sync_regs(fbi);
>  
>  	/* ensure the panel interface is not tristated at this point */
> @@ -924,7 +925,7 @@ static int sm501fb_setcolreg(unsigned regno,
>  			val |= (green >> 8) << 8;
>  			val |= blue >> 8;
>  
> -			writel(val, base + (regno * 4));
> +			smc501_writel(val, base + (regno * 4));
>  		}
>  
>  		break;
> @@ -980,7 +981,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
>  
>  	dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info);
>  
> -	ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL);
> +	ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL);
>  
>  	switch (blank_mode) {
>  	case FB_BLANK_POWERDOWN:
> @@ -1004,7 +1005,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info)
>  
>  	}
>  
> -	writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
> +	smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL);
>  	sm501fb_sync_regs(fbi);
>  
>  	return 0;
> @@ -1041,12 +1042,14 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
>  	if (cursor->image.depth > 1)
>  		return -EINVAL;
>  
> -	hwc_addr = readl(base + SM501_OFF_HWC_ADDR);
> +	hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR);
>  
>  	if (cursor->enable)
> -		writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
> +		smc501_writel(hwc_addr | SM501_HWC_EN,
> +				base + SM501_OFF_HWC_ADDR);
>  	else
> -		writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR);
> +		smc501_writel(hwc_addr & ~SM501_HWC_EN,
> +				base + SM501_OFF_HWC_ADDR);
>  
>  	/* set data */
>  	if (cursor->set & FB_CUR_SETPOS) {
> @@ -1060,7 +1063,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
>  
>  		//y += cursor->image.height;
>  
> -		writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
> +		smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC);
>  	}
>  
>  	if (cursor->set & FB_CUR_SETCMAP) {
> @@ -1080,8 +1083,8 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
>  
>  		dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
>  
> -		writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
> -		writel(fg, base + SM501_OFF_HWC_COLOR_3);
> +		smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
> +		smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3);
>  	}
>  
>  	if (cursor->set & FB_CUR_SETSIZE ||
> @@ -1102,7 +1105,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
>  			__func__, cursor->image.width, cursor->image.height);
>  
>  		for (op = 0; op < (64*64*2)/8; op+=4)
> -			writel(0x0, dst + op);
> +			smc501_writel(0x0, dst + op);
>  
>  		for (y = 0; y < cursor->image.height; y++) {
>  			for (x = 0; x < cursor->image.width; x++) {
> @@ -1141,7 +1144,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev,
>  	struct sm501fb_info *info = dev_get_drvdata(dev);
>  	unsigned long ctrl;
>  
> -	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +	ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
>  	ctrl &= SM501_DC_CRT_CONTROL_SEL;
>  
>  	return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel");
> @@ -1172,7 +1175,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
>  
>  	dev_info(dev, "setting crt source to head %d\n", head);
>  
> -	ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +	ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
>  
>  	if (head == HEAD_CRT) {
>  		ctrl |= SM501_DC_CRT_CONTROL_SEL;
> @@ -1184,7 +1187,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev,
>  		ctrl &= ~SM501_DC_CRT_CONTROL_TE;
>  	}
>  
> -	writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
> +	smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
>  	sm501fb_sync_regs(info);
>  
>  	return len;
> @@ -1205,7 +1208,8 @@ static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr,
>  	unsigned int reg;
>  
>  	for (reg = start; reg < (len + start); reg += 4)
> -		ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg));
> +		ptr += sprintf(ptr, "%08x = %08x\n", reg,
> +				smc501_readl(mem + reg));
>  
>  	return ptr - buf;
>  }
> @@ -1257,7 +1261,7 @@ static int sm501fb_sync(struct fb_info *info)
>  
>  	/* wait for the 2d engine to be ready */
>  	while ((count > 0) &&
> -	       (readl(fbi->regs + SM501_SYSTEM_CONTROL) &
> +	       (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) &
>  		SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
>  		count--;
>  
> @@ -1312,45 +1316,46 @@ static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *are
>  		return;
>  
>  	/* set the base addresses */
> -	writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
> -	writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
> +	smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
> +	smc501_writel(par->screen.sm_addr,
> +			fbi->regs2d + SM501_2D_DESTINATION_BASE);
>  
>  	/* set the window width */
> -	writel((info->var.xres << 16) | info->var.xres,
> +	smc501_writel((info->var.xres << 16) | info->var.xres,
>  	       fbi->regs2d + SM501_2D_WINDOW_WIDTH);
>  
>  	/* set window stride */
> -	writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
> +	smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
>  	       fbi->regs2d + SM501_2D_PITCH);
>  
>  	/* set data format */
>  	switch (info->var.bits_per_pixel) {
>  	case 8:
> -		writel(0, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	case 16:
> -		writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	case 32:
> -		writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	}
>  
>  	/* 2d compare mask */
> -	writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
> +	smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
>  
>  	/* 2d mask */
> -	writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
> +	smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
>  
>  	/* source and destination x y */
> -	writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
> -	writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
> +	smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
> +	smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
>  
>  	/* w/h */
> -	writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
> +	smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
>  
>  	/* do area move */
> -	writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
> +	smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
>  }
>  
>  static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
> @@ -1372,47 +1377,49 @@ static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rec
>  		return;
>  
>  	/* set the base addresses */
> -	writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
> -	writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
> +	smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
> +	smc501_writel(par->screen.sm_addr,
> +			fbi->regs2d + SM501_2D_DESTINATION_BASE);
>  
>  	/* set the window width */
> -	writel((info->var.xres << 16) | info->var.xres,
> +	smc501_writel((info->var.xres << 16) | info->var.xres,
>  	       fbi->regs2d + SM501_2D_WINDOW_WIDTH);
>  
>  	/* set window stride */
> -	writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
> +	smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
>  	       fbi->regs2d + SM501_2D_PITCH);
>  
>  	/* set data format */
>  	switch (info->var.bits_per_pixel) {
>  	case 8:
> -		writel(0, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	case 16:
> -		writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	case 32:
> -		writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
> +		smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
>  		break;
>  	}
>  
>  	/* 2d compare mask */
> -	writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
> +	smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
>  
>  	/* 2d mask */
> -	writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
> +	smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
>  
>  	/* colour */
> -	writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
> +	smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
>  
>  	/* x y */
> -	writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION);
> +	smc501_writel((rect->dx << 16) | rect->dy,
> +			fbi->regs2d + SM501_2D_DESTINATION);
>  
>  	/* w/h */
> -	writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
> +	smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
>  
>  	/* do rectangle fill */
> -	writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
> +	smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
>  }
>  
>  
> @@ -1470,11 +1477,12 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
>  
>  	/* initialise the colour registers */
>  
> -	writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR);
> +	smc501_writel(par->cursor.sm_addr,
> +			par->cursor_regs + SM501_OFF_HWC_ADDR);
>  
> -	writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
> -	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
> -	writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
> +	smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC);
> +	smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2);
> +	smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3);
>  	sm501fb_sync_regs(info);
>  
>  	return 0;
> @@ -1581,7 +1589,7 @@ static int sm501fb_start(struct sm501fb_info *info,
>  
>  	/* clear palette ram - undefined at power on */
>  	for (k = 0; k < (256 * 3); k++)
> -		writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
> +		smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4));
>  
>  	/* enable display controller */
>  	sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
> @@ -1649,20 +1657,20 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  	switch (head) {
>  	case HEAD_CRT:
>  		pd = info->pdata->fb_crt;
> -		ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +		ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
>  		enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0;
>  
>  		/* ensure we set the correct source register */
>  		if (info->pdata->fb_route != SM501_FB_CRT_PANEL) {
>  			ctrl |= SM501_DC_CRT_CONTROL_SEL;
> -			writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
> +			smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
>  		}
>  
>  		break;
>  
>  	case HEAD_PANEL:
>  		pd = info->pdata->fb_pnl;
> -		ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL);
> +		ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL);
>  		enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0;
>  		break;
>  
> @@ -1680,7 +1688,7 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  
>  	if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) {
>  		ctrl &= ~SM501_DC_CRT_CONTROL_SEL;
> -		writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
> +		smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL);
>  		enable = 0;
>  	}
>  
> @@ -2085,7 +2093,7 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
>  	struct sm501fb_info *info = platform_get_drvdata(pdev);
>  
>  	/* store crt control to resume with */
> -	info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +	info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
>  
>  	sm501fb_suspend_fb(info, HEAD_CRT);
>  	sm501fb_suspend_fb(info, HEAD_PANEL);
> @@ -2109,10 +2117,10 @@ static int sm501fb_resume(struct platform_device *pdev)
>  
>  	/* restore the items we want to be saved for crt control */
>  
> -	crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
> +	crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
>  	crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
>  	crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
> -	writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
> +	smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
>  
>  	sm501fb_resume_fb(info, HEAD_CRT);
>  	sm501fb_resume_fb(info, HEAD_PANEL);
> diff --git a/include/linux/sm501.h b/include/linux/sm501.h
> index 214f932..02fde50 100644
> --- a/include/linux/sm501.h
> +++ b/include/linux/sm501.h
> @@ -172,3 +172,11 @@ struct sm501_platdata {
>  	struct sm501_platdata_gpio_i2c	*gpio_i2c;
>  	unsigned int			 gpio_i2c_nr;
>  };
> +
> +#if defined(CONFIG_PPC32)
> +#define smc501_readl(addr)		ioread32be((addr))
> +#define smc501_writel(val, addr)	iowrite32be((val), (addr))
> +#else
> +#define smc501_readl(addr)		readl(addr)
> +#define smc501_writel(val, addr)	writel(val, addr)
> +#endif
> -- 
> 1.7.4
> 

^ permalink raw reply

* Re: [PATCH v6 0/6] powerpc, 52xx: add charon board support
From: Grant Likely @ 2011-05-02 22:14 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linux-fbdev, devicetree-discuss, Samuel Ortiz, Vincent Sanders,
	linux-kernel, Ben Dooks, Randy Dunlap, Paul Mundt, linuxppc-dev,
	Wolfgang Denk
In-Reply-To: <1300782452-528-1-git-send-email-hs@denx.de>

On Tue, Mar 22, 2011 at 09:27:26AM +0100, Heiko Schocher wrote:
> cc: Wolfram Sang <w.sang@pengutronix.de>
> cc: Grant Likely <grant.likely@secretlab.ca>
> cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> cc: Randy Dunlap <rdunlap@xenotime.net>
> cc: Wolfgang Denk <wd@denx.de>
> cc: Paul Mundt <lethal@linux-sh.org>
> 
> changes since v5:
> - repost complete patchseries, as Paul Mundt suggested
> - rebased against current head
> - add Acked-by from Samuel Ortiz (MFD parts)
>   http://www.spinics.net/lists/linux-fbdev/msg02550.html
>   http://linux.derkeiler.com/Mailing-Lists/Kernel/2011-01/msg11798.html
> 
>   and Benjamin Herrenschmidt (DTS parts)
>   http://lists.ozlabs.org/pipermail/linuxppc-dev/2011-February/088279.html
> - removed patch 
>   "powerpc, mpc5200: update mpc5200_defconfig to fit for charon board."
>   therefore added
>   "powerpc, tqm5200: update tqm5200_defconfig to fit for charon board."

Refresh my memory, why was the mpc5200_defconfig updated dropped?

g.

^ permalink raw reply

* Re: Login prompt on a video console instead of serial port?
From: Grant Likely @ 2011-05-02 20:12 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linux-fbdev, devicetree-discuss, linuxppc-dev
In-Reply-To: <4DBF065C.3030407@freescale.com>

On Mon, May 2, 2011 at 1:30 PM, Timur Tabi <timur@freescale.com> wrote:
> I'm using a Freescale P1022DS (PowerPC e500 core) system, which has a bui=
lt-in
> video controller. =A0I have a framebuffer driver that works fine, and if =
I add
> "video=3Dfslfb:1280x1024-32@60,monitor=3D0 console=3Dtty0" to the command=
-line, then
> *most* of the kernel boot log appears on the serial port and the video di=
splay.
>
> However, the login prompt is always on the serial port. =A0This happens e=
ven if I
> delete the "console=3DttyS0,115200" from the command-line. =A0I presume t=
his is
> because the "linux,stdout-path" property in the device tree always points=
 to a
> serial port node.
>
> So my question is: what do I need to do get the login prompt on the video
> console? =A0That is, stdout goes to /dev/fb0 but stdin is still from /dev=
/ttyS0.
> I presume I need to direct "linux,stdout-path" to the fslfb node in the d=
evice
> tree, but there doesn't appear to be support for "linux,stdin-path".

Look in /etc/inittab.  That's usually where the login gettys are specified.

g.

>
> --
> Timur Tabi
> Linux kernel developer at Freescale
>
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss
>



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

^ permalink raw reply

* Re: Login prompt on a video console instead of serial port?
From: Timur Tabi @ 2011-05-02 20:02 UTC (permalink / raw)
  To: McClintock Matthew-B29882
  Cc: devicetree-discuss, linuxppc-dev@lists.ozlabs.org,
	linux-fbdev@vger.kernel.org
In-Reply-To: <BANLkTikWMksVsvs8KzjdiZfRR-2WGD0Ftw@mail.gmail.com>

McClintock Matthew-B29882 wrote:
> Don't you have to spawn a terminal on the framebuffer for the login?

I suppose, but I don't know how to do that.  And although that would technically
answer the question in the subject of this thread, I still would have *some*
boot output on the serial port.  It would be nice if I could get all of stdout
on the video display, and all of stdin from the serial port.

> Right now getty spawns the login on the serial port via /etc/inittab.
> Something similiar is probably needed for the framebuffer.

getty appears to work only with serial devices, since it insists on a baud rate
as one of the parameters.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: Login prompt on a video console instead of serial port?
From: McClintock Matthew-B29882 @ 2011-05-02 19:55 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: linux-fbdev@vger.kernel.org, devicetree-discuss,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4DBF065C.3030407@freescale.com>

Don't you have to spawn a terminal on the framebuffer for the login?
Right now getty spawns the login on the serial port via /etc/inittab.
Something similiar is probably needed for the framebuffer.

-M



On Mon, May 2, 2011 at 2:30 PM, Timur Tabi <timur@freescale.com> wrote:
> I'm using a Freescale P1022DS (PowerPC e500 core) system, which has a bui=
lt-in
> video controller. =A0I have a framebuffer driver that works fine, and if =
I add
> "video=3Dfslfb:1280x1024-32@60,monitor=3D0 console=3Dtty0" to the command=
-line, then
> *most* of the kernel boot log appears on the serial port and the video di=
splay.
>
> However, the login prompt is always on the serial port. =A0This happens e=
ven if I
> delete the "console=3DttyS0,115200" from the command-line. =A0I presume t=
his is
> because the "linux,stdout-path" property in the device tree always points=
 to a
> serial port node.
>
> So my question is: what do I need to do get the login prompt on the video
> console? =A0That is, stdout goes to /dev/fb0 but stdin is still from /dev=
/ttyS0.
> I presume I need to direct "linux,stdout-path" to the fslfb node in the d=
evice
> tree, but there doesn't appear to be support for "linux,stdin-path".=

^ 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