* [PATCH 2/5] Removing dead CONFIG_HIGHPTE
From: Christoph Egger @ 2010-06-09 9:59 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Albert Herranz,
Grant Likely, Li Yang, Tejun Heo, linuxppc-dev, linux-kernel
Cc: vamos
In-Reply-To: <cover.1275925219.git.siccegge@cs.fau.de>
CONFIG_HIGHPTE doesn't exist in Kconfig, therefore removing all
references for it from the source code.
Signed-off-by: Christoph Egger <siccegge@cs.fau.de>
---
arch/powerpc/mm/pgtable_32.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 9fc02dc..34347b2 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -115,11 +115,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
struct page *ptepage;
-#ifdef CONFIG_HIGHPTE
- gfp_t flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT | __GFP_ZERO;
-#else
gfp_t flags = GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO;
-#endif
ptepage = alloc_pages(flags, 0);
if (!ptepage)
--
1.6.3.3
^ permalink raw reply related
* [PATCH 5/5] Removing dead CONFIG_PPC47x
From: Christoph Egger @ 2010-06-09 10:01 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Stephen Rothwell,
Torez Smith, Dave Kleikamp, Josh Boyer, linuxppc-dev,
linux-kernel
Cc: vamos
In-Reply-To: <cover.1275925219.git.siccegge@cs.fau.de>
CONFIG_PPC47x doesn't exist in Kconfig, therefore removing all
references for it from the source code.
Signed-off-by: Christoph Egger <siccegge@cs.fau.de>
---
arch/powerpc/mm/44x_mmu.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index d8c6efb..f70da7e 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -76,11 +76,7 @@ static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
"tlbwe %1,%3,%5\n"
"tlbwe %0,%3,%6\n"
:
-#ifdef CONFIG_PPC47x
- : "r" (PPC47x_TLB2_S_RWX),
-#else
: "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
-#endif
"r" (phys),
"r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M),
"r" (entry),
--
1.6.3.3
^ permalink raw reply related
* [PATCH 4/5] Removing dead CONFIG_SERIAL_TEXT_DEBUG
From: Christoph Egger @ 2010-06-09 10:00 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev,
linux-kernel; +Cc: vamos
In-Reply-To: <cover.1275925219.git.siccegge@cs.fau.de>
CONFIG_SERIAL_TEXT_DEBUG doesn't exist in Kconfig, therefore removing all
references for it from the source code.
Signed-off-by: Christoph Egger <siccegge@cs.fau.de>
---
arch/powerpc/kernel/head_40x.S | 19 -------------------
1 files changed, 0 insertions(+), 19 deletions(-)
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index a90625f..1a10e4d 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -939,25 +939,6 @@ initial_mmu:
tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */
tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(SERIAL_DEBUG_IO_BASE)
-
- /* Load a TLB entry for the UART, so that ppc4xx_progress() can use
- * the UARTs nice and early. We use a 4k real==virtual mapping. */
-
- lis r3,SERIAL_DEBUG_IO_BASE@h
- ori r3,r3,SERIAL_DEBUG_IO_BASE@l
- mr r4,r3
- clrrwi r4,r4,12
- ori r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G)
-
- clrrwi r3,r3,12
- ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
-
- li r0,0 /* TLB slot 0 */
- tlbwe r4,r0,TLB_DATA
- tlbwe r3,r0,TLB_TAG
-#endif /* CONFIG_SERIAL_DEBUG_TEXT && SERIAL_DEBUG_IO_BASE */
-
isync
/* Establish the exception vector base
--
1.6.3.3
^ permalink raw reply related
* Re: [PATCH 00/12] treewide: Remove unnecessary kmalloc casts
From: Pekka Enberg @ 2010-06-09 10:06 UTC (permalink / raw)
To: Milton Miller; +Cc: Joe Perches, Andrew Morton, linuxppc-dev, linux-kernel
In-Reply-To: <1276068001_13533@mail4.comsite.net>
Hi Milton,
On Wed, Jun 9, 2010 at 10:20 AM, Milton Miller <miltonm@bga.com> wrote:
> However, in this case you are removing casts that, while not necessary
> for C, are indeed there for a reason.
>
> Specifically, they are of the form
> =A0 type *p;
> =A0 <code>
> =A0 p =3D (type *)kmalloc(sizeof(type), ...);
>
> For example, from the powerpc patch:
>> goto out;
>> }
>> - tmp_part =3D (struct nvram_partition *)
>> - kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
>> + tmp_part =3D kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
>> err =3D -ENOMEM;
>
> The reason they casts are present is to guard against someone changing
> the type of p at the top of the function and not changing the type at
> the kmalloc.
If you're worried about that...
[snip]
> There may have been discussion of doing the above vs
> =A0 p =3D kmalloc(sizeof(*p), ...);
...it's better to use this form. There's actually a mention of this in
"Chapter 14: Allocating memory" of Documentation/CodingStyle. The
guard is not really a guard as someone can still change the "sizeof"
part to something else and the cast from "void *" will silently ignore
it.
Pekka
^ permalink raw reply
* [PATCH 0/5] Removing dead code
From: Christoph Egger @ 2010-06-09 9:58 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Kumar Gala,
Stephen Rothwell, Torez Smith, Dave Kleikamp, Josh Boyer,
Albert Herranz, Grant Likely, Li Yang, Tejun Heo,
Thadeu Lima de Souza Cascardo, Huang Weiyi, linuxppc-dev,
linux-kernel
Cc: vamos
Hi all!
As part of the VAMOS[0] research project at the University of
Erlangen we are looking at multiple integrity errors in linux'
configuration system.
I've been running a check on the arch/powerpc sourcetree
for
config Items not defined in Kconfig and found5 such chases. Sourcecode
blocks depending on these Items are not reachable from a vanilla
kernel -- dead code. I've seen such dead blocks made on purpose
e.g. while integrating new features into the kernel but generally
they're just useless.
Each of the patches in this patchset removes on such dead
config Item, I'd be glad if you consider applying them. I've been
doing deeper analysis of such issues before and can do so again but
I'm not so sure they were fastly usefull. However I've done a
testbuild on ppc with allmodconfig so it should at least build.
Please keep me informed of this patch getting confirmed /
merged so we can keep track of it.
Regards
Christoph Egger
[0] http://vamos1.informatik.uni-erlangen.de/
Christoph Egger (5):
Removing dead BOOK3E_MMU_TLB_STATS
Removing dead CONFIG_HIGHPTE
Removing dead CONFIG_SMP_750
Removing dead CONFIG_SERIAL_TEXT_DEBUG
Removing dead CONFIG_PPC47x
arch/powerpc/include/asm/exception-64e.h | 38 ------------------------------
arch/powerpc/kernel/head_40x.S | 19 ---------------
arch/powerpc/mm/44x_mmu.c | 4 ---
arch/powerpc/mm/pgtable_32.c | 4 ---
arch/powerpc/mm/tlb_hash32.c | 4 ---
arch/powerpc/mm/tlb_low_64e.S | 9 -------
6 files changed, 0 insertions(+), 78 deletions(-)
^ permalink raw reply
* Re: [PATCH 3/3] powerpc: enabled asymmetric SMT scheduling on POWER7
From: Benjamin Herrenschmidt @ 2010-06-09 8:54 UTC (permalink / raw)
To: Michael Neuling; +Cc: Peter Zijlstra, linuxppc-dev, linux-kernel
In-Reply-To: <20100608045702.31FB5CC8C7@localhost.localdomain>
On Tue, 2010-06-08 at 14:57 +1000, Michael Neuling wrote:
> The POWER7 core has dynamic SMT mode switching which is controlled by
> the hypervisor. There are 3 SMT modes:
> SMT1 uses thread 0
> SMT2 uses threads 0 & 1
> SMT4 uses threads 0, 1, 2 & 3
> When in any particular SMT mode, all threads have the same performance
> as each other (ie. at any moment in time, all threads perform the same).
>
> The SMT mode switching works such that when linux has threads 2 & 3 idle
> and 0 & 1 active, it will cede (H_CEDE hypercall) threads 2 and 3 in the
> idle loop and the hypervisor will automatically switch to SMT2 for that
> core (independent of other cores). The opposite is not true, so if
> threads 0 & 1 are idle and 2 & 3 are active, we will stay in SMT4 mode.
>
> Similarly if thread 0 is active and threads 1, 2 & 3 are idle, we'll go
> into SMT1 mode.
>
> If we can get the core into a lower SMT mode (SMT1 is best), the threads
> will perform better (since they share less core resources). Hence when
> we have idle threads, we want them to be the higher ones.
>
> This adds a feature bit for asymmetric packing to powerpc and then
> enables it on POWER7.
>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>
> ---
>
> arch/powerpc/include/asm/cputable.h | 3 ++-
> arch/powerpc/kernel/process.c | 9 +++++++++
> 2 files changed, 11 insertions(+), 1 deletion(-)
>
> Index: linux-2.6-ozlabs/arch/powerpc/include/asm/cputable.h
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/include/asm/cputable.h
> +++ linux-2.6-ozlabs/arch/powerpc/include/asm/cputable.h
> @@ -195,6 +195,7 @@ extern const char *powerpc_base_platform
> #define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000)
> #define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
> #define CPU_FTR_UNALIGNED_LD_STD LONG_ASM_CONST(0x0080000000000000)
> +#define CPU_FTR_ASYM_SMT LONG_ASM_CONST(0x0100000000000000)
>
> #ifndef __ASSEMBLY__
>
> @@ -409,7 +410,7 @@ extern const char *powerpc_base_platform
> CPU_FTR_MMCRA | CPU_FTR_SMT | \
> CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
> CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
> - CPU_FTR_DSCR | CPU_FTR_SAO)
> + CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT)
> #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-2.6-ozlabs/arch/powerpc/kernel/process.c
> ===================================================================
> --- linux-2.6-ozlabs.orig/arch/powerpc/kernel/process.c
> +++ linux-2.6-ozlabs/arch/powerpc/kernel/process.c
> @@ -1265,3 +1265,12 @@ unsigned long randomize_et_dyn(unsigned
>
> return ret;
> }
> +
> +int arch_sd_sibiling_asym_packing(void)
> +{
> + if (cpu_has_feature(CPU_FTR_ASYM_SMT)){
> + printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
> + return SD_ASYM_PACKING;
> + }
> + return 0;
> +}
^ permalink raw reply
* Re: [PATCH 00/12] treewide: Remove unnecessary kmalloc casts
From: Joe Perches @ 2010-06-09 7:46 UTC (permalink / raw)
To: Milton Miller, Jiri Kosina; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1276068001_13533@mail4.comsite.net>
On Wed, 2010-06-09 at 02:20 -0500, Milton Miller wrote:
> On Mon Jun 07 2010 at around 23:53:18 EST, Joe Perches wrote:
> > Trivial cleanups
> The reason they casts are present is to guard against someone changing
> the type of p at the top of the function and not changing the type at
> the kmalloc.
That'd be true for most all of the kernel mallocs.
> I know some maintainers have already taken some of
> the series the last time you posted; could you please augment the
> CC list.
I did not send to trivial any of kmalloc cast removal patches that
were acked. The patches in this series were not acked, so I think
no CC list needs augmentation.
Original: http://lkml.org/lkml/2010/5/31/471
Newest: http://lkml.org/lkml/2010/6/7/428
cheers, Joe
^ permalink raw reply
* Re: [PATCH 00/12] treewide: Remove unnecessary kmalloc casts
From: Milton Miller @ 2010-06-09 7:20 UTC (permalink / raw)
To: Joe Perches; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1275968594.git.joe@perches.com>
On Mon Jun 07 2010 at around 23:53:18 EST, Joe Perches wrote:
> Trivial cleanups
>
> arch/cris: Remove unnecessary kmalloc casts
> arch/powerpc: Remove unnecessary kmalloc casts
> arch/x86/kernel/tlb_uv.c: Remove unnecessary kmalloc casts
> drivers/gpu/drm: Remove unnecessary kmalloc casts
> drivers/isdn/capi/capidrv.c: Remove unnecessary kmalloc casts
> drivers/media: Remove unnecesary kmalloc casts
> drivers/message/i2o/i20_config.c: Remove unnecessary kmalloc casts
> drivers/parisc/iosapic.c: Remove unnecessary kzalloc cast
> drivers/s390: Remove unnecessary kmalloc casts
> drivers/serial/icom.c: Remove unnecessary kmalloc casts
> drivers/usb/storage/isd200.c: Remove unnecessary kmalloc casts
> fs/ufs/util.c: Remove unnecessary kmalloc casts
>
Joe,
Thanks for doing cleanups.
However, in this case you are removing casts that, while not necessary
for C, are indeed there for a reason.
Specifically, they are of the form
type *p;
<code>
p = (type *)kmalloc(sizeof(type), ...);
For example, from the powerpc patch:
> goto out;
> }
> - tmp_part = (struct nvram_partition *)
> - kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
> + tmp_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
> err = -ENOMEM;
The reason they casts are present is to guard against someone changing
the type of p at the top of the function and not changing the type at
the kmalloc.
This was discussed some years ago, possibly around the time kcalloc
got its underflow detection.
Should we create a kmalloc wrapper that enforces this type saftey?
While we have added static analysis tools that can check these things,
and we have slab redzoning options, they tend to be run in batch by
"someone else" or in response to debugging a problem.
There may have been discussion of doing the above vs
p = kmalloc(sizeof(*p), ...);
I don't remember if it was programmer preference or issues when p is
an array type.
I am not subscribed so I don't have the full list that you sent
these to, and I know some maintainers have already taken some of
the series the last time you posted; could you please augment the
CC list.
thanks,
milton
^ permalink raw reply
* Re: [PATCH 0/2] mpc5200 ac97 gpio reset
From: Wolfgang Denk @ 2010-06-09 6:13 UTC (permalink / raw)
To: Jon Smirl; +Cc: Mark Brown, linuxppc-dev, Eric Millbrandt
In-Reply-To: <AANLkTimIs90kR5uqhdBQ02oSd94dn08sOITm51Ylrl4-@mail.gmail.com>
Dear Jon Smirl,
In message <AANLkTimIs90kR5uqhdBQ02oSd94dn08sOITm51Ylrl4-@mail.gmail.com> you wrote:
>
> Would making a change in uboot be a better solution? Eric, can you
> verify if changing uboot also fixes the problem?
To me it seems better if the driver itself does what needs to be done
instead of relying on specific settings that may or may not be done in
U-Boot. Keep in mind that drivers may be loaded as modules, and that
we even see cases where the same port serves multiple purposes by
loading different driver modules (yes, this is not exactly a clever
idea, but hardware designers come up with such solutions).
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
The typical page layout program is nothing more than an electronic
light table for cutting and pasting documents.
^ permalink raw reply
* [PATCH] powerpc: rtas_flash cannot be a module
From: Anton Blanchard @ 2010-06-09 6:01 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev
When trying to flash a machine via the update_flash command, I received the
following error:
Restarting system.
FLASH: kernel bug...flash list header addr above 4GB
The code in question has a comment that the flash list should be in
the kernel data and therefore under 4GB:
/* NOTE: the "first" block list is a global var with no data
* blocks in the kernel data segment. We do this because
* we want to ensure this block_list addr is under 4GB.
*/
Unfortunately the Kconfig option is marked tristate which means the variable
may not be in the kernel data and could be above 4GB.
Change RTAS_FLASH to a bool. If we are worried about kernel footprint we
could move the problem variables out of the module and export them.
Signed-off-by: Anton Blanchard <anton@samba.org>
---
Index: linux-2.6/arch/powerpc/platforms/Kconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/platforms/Kconfig 2010-06-09 15:44:53.635955260 +1000
+++ linux-2.6/arch/powerpc/platforms/Kconfig 2010-06-09 15:45:00.503453428 +1000
@@ -97,7 +97,7 @@ config RTAS_PROC
default y
config RTAS_FLASH
- tristate "Firmware flash interface"
+ bool "Firmware flash interface"
depends on PPC64 && RTAS_PROC
config MMIO_NVRAM
Index: linux-2.6/arch/powerpc/configs/ppc64_defconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/configs/ppc64_defconfig 2010-06-09 15:46:25.394704486 +1000
+++ linux-2.6/arch/powerpc/configs/ppc64_defconfig 2010-06-09 15:46:37.083454943 +1000
@@ -264,7 +264,7 @@ CONFIG_U3_DART=y
CONFIG_PPC_RTAS=y
CONFIG_RTAS_ERROR_LOGGING=y
CONFIG_RTAS_PROC=y
-CONFIG_RTAS_FLASH=m
+CONFIG_RTAS_FLASH=y
CONFIG_PPC_PMI=m
CONFIG_MMIO_NVRAM=y
CONFIG_MPIC_U3_HT_IRQS=y
Index: linux-2.6/arch/powerpc/configs/pseries_defconfig
===================================================================
--- linux-2.6.orig/arch/powerpc/configs/pseries_defconfig 2010-06-09 15:46:25.364703092 +1000
+++ linux-2.6/arch/powerpc/configs/pseries_defconfig 2010-06-09 15:46:31.723454300 +1000
@@ -213,7 +213,7 @@ CONFIG_PPC_I8259=y
CONFIG_PPC_RTAS=y
CONFIG_RTAS_ERROR_LOGGING=y
CONFIG_RTAS_PROC=y
-CONFIG_RTAS_FLASH=m
+CONFIG_RTAS_FLASH=y
# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
CONFIG_IBMEBUS=y
^ permalink raw reply
* Re: [PATCH 0/2] mpc5200 ac97 gpio reset
From: Jon Smirl @ 2010-06-09 0:24 UTC (permalink / raw)
To: Eric Millbrandt; +Cc: Mark Brown, linuxppc-dev
In-Reply-To: <1276015562-28928-1-git-send-email-emillbrandt@dekaresearch.com>
On Tue, Jun 8, 2010 at 12:46 PM, Eric Millbrandt
<emillbrandt@dekaresearch.com> wrote:
> These patches reimplement the reset fuction in the ac97 to use gpio pins
> instead of using the mpc5200 ac97 reset functionality in the psc. =A0This
> avoids a problem in which attached ac97 devices go into "test" mode appea=
r
> unresponsive.
I'm aware of this problem but I was unable to solve it when I first
wrote the driver. I didn't have access to a scope so I wasn't able to
figure out what was causing the lock up. I worked around it by
looping in reset until the chip did actually reset, but Mark wouldn't
let me submit that code.
A while ago Maximilian Mueth <maximilian.mueth@mp-ndt.de> sent me a
note saying another solution was to configure the PSC into AC97 mode
in uboot. His impression was that uboot was setting PSC into its
default mode. Then Linux booted and set the PSC into AC97 mode. The
transition from default mode into AC97 mode caused glitches on the
AC97 reset pins and triggered test mode.
Would making a change in uboot be a better solution? Eric, can you
verify if changing uboot also fixes the problem?
I'm glad were finally getting to the root cause of the problem.
>
> These patches were tested on a pcm030 baseboard and on custom hardware wi=
th
> a wm9715 audio codec/touchscreen controller.
>
> Eric Millbrandt
>
> ---
>
> Eric Millbrandt (2):
> =A0 =A0powerpc/5200: Export port-config
> =A0 =A0sound/soc: mpc5200_psc_ac97: Use gpio pins for cold reset.
>
> =A0arch/powerpc/boot/dts/lite5200.dts =A0 =A0 =A0 =A0 =A0 | =A0 =A03 +
> =A0arch/powerpc/boot/dts/lite5200b.dts =A0 =A0 =A0 =A0 =A0| =A0 =A03 +
> =A0arch/powerpc/boot/dts/pcm030.dts =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A03 +
> =A0arch/powerpc/boot/dts/pcm032.dts =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A03 +
> =A0arch/powerpc/include/asm/mpc52xx.h =A0 =A0 =A0 =A0 =A0 | =A0 =A02 +
> =A0arch/powerpc/platforms/52xx/mpc52xx_common.c | =A0 61 ++++++++++++++++=
+++
> =A0sound/soc/fsl/mpc5200_dma.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =
=A05 ++
> =A0sound/soc/fsl/mpc5200_psc_ac97.c =A0 =A0 =A0 =A0 =A0 =A0 | =A0 83 ++++=
++++++++++++++++++++-
> =A08 files changed, 159 insertions(+), 4 deletions(-)
>
> -DISCLAIMER: an automatically appended disclaimer may follow. By posting-
> -to a public e-mail mailing list I hereby grant permission to distribute-
> -and copy this message.-
>
>
> This e-mail and the information, including any attachments, it contains a=
re intended to be a confidential communication only to the person or entity=
to whom it is addressed and may contain information that is privileged. If=
the reader of this message is not the intended recipient, you are hereby n=
otified that any dissemination, distribution or copying of this communicati=
on is strictly prohibited. If you have received this communication in error=
, please immediately notify the sender and destroy the original message.
>
> Thank you.
>
> Please consider the environment before printing this email.
>
--=20
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* [PATCH 3/3] powerpc/85xx: Cleanup QE initialization for MPC85xxMDS boards
From: Anton Vorontsov @ 2010-06-08 19:55 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
The mpc85xx_mds_setup_arch() function is incomprehensible
and unmaintainable. Factor out all QE specific stuff into
mpc85xx_mds_qe_init() and mpc85xx_mds_reset_ucc_phys().
Also move QE stuff out of mpc85xx_mds_pic_init().
The diff is unreadable, but only because the code was so. ;-)
It should be better now, and less indented.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 272 +++++++++++++++--------------
1 files changed, 143 insertions(+), 129 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 9dadcff..c8be7b5 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -177,63 +177,89 @@ static void __init mpc85xx_publish_qe_devices(void)
of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL);
}
-#else
-static void __init mpc85xx_publish_qe_devices(void) { }
-#endif /* CONFIG_QUICC_ENGINE */
-static void __init mpc85xx_mds_setup_arch(void)
+static void __init mpc85xx_mds_reset_ucc_phys(void)
{
struct device_node *np;
- static u8 __iomem *bcsr_regs = NULL;
-#ifdef CONFIG_PCI
- struct pci_controller *hose;
-#endif
- dma_addr_t max = 0xffffffff;
-
- if (ppc_md.progress)
- ppc_md.progress("mpc85xx_mds_setup_arch()", 0);
+ static u8 __iomem *bcsr_regs;
/* Map BCSR area */
np = of_find_node_by_name(NULL, "bcsr");
- if (np != NULL) {
- struct resource res;
+ if (!np)
+ return;
- of_address_to_resource(np, 0, &res);
- bcsr_regs = ioremap(res.start, res.end - res.start +1);
- of_node_put(np);
- }
+ bcsr_regs = of_iomap(np, 0);
+ of_node_put(np);
+ if (!bcsr_regs)
+ return;
-#ifdef CONFIG_PCI
- for_each_node_by_type(np, "pci") {
- if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
- of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
- struct resource rsrc;
- of_address_to_resource(np, 0, &rsrc);
- if ((rsrc.start & 0xfffff) == 0x8000)
- fsl_add_bridge(np, 1);
- else
- fsl_add_bridge(np, 0);
+ if (machine_is(mpc8568_mds)) {
+#define BCSR_UCC1_GETH_EN (0x1 << 7)
+#define BCSR_UCC2_GETH_EN (0x1 << 7)
+#define BCSR_UCC1_MODE_MSK (0x3 << 4)
+#define BCSR_UCC2_MODE_MSK (0x3 << 0)
- hose = pci_find_hose_for_OF_device(np);
- max = min(max, hose->dma_window_base_cur +
- hose->dma_window_size);
+ /* Turn off UCC1 & UCC2 */
+ clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
+ clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
+
+ /* Mode is RGMII, all bits clear */
+ clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK |
+ BCSR_UCC2_MODE_MSK);
+
+ /* Turn UCC1 & UCC2 on */
+ setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
+ setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
+ } else if (machine_is(mpc8569_mds)) {
+#define BCSR7_UCC12_GETHnRST (0x1 << 2)
+#define BCSR8_UEM_MARVELL_RST (0x1 << 1)
+#define BCSR_UCC_RGMII (0x1 << 6)
+#define BCSR_UCC_RTBI (0x1 << 5)
+ /*
+ * U-Boot mangles interrupt polarity for Marvell PHYs,
+ * so reset built-in and UEM Marvell PHYs, this puts
+ * the PHYs into their normal state.
+ */
+ clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+ setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
+ clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
+
+ for (np = NULL; (np = of_find_compatible_node(np,
+ "network",
+ "ucc_geth")) != NULL;) {
+ const unsigned int *prop;
+ int ucc_num;
+
+ prop = of_get_property(np, "cell-index", NULL);
+ if (prop == NULL)
+ continue;
+
+ ucc_num = *prop - 1;
+
+ prop = of_get_property(np, "phy-connection-type", NULL);
+ if (prop == NULL)
+ continue;
+
+ if (strcmp("rtbi", (const char *)prop) == 0)
+ clrsetbits_8(&bcsr_regs[7 + ucc_num],
+ BCSR_UCC_RGMII, BCSR_UCC_RTBI);
}
+ } else if (machine_is(p1021_mds)) {
+#define BCSR11_ENET_MICRST (0x1 << 5)
+ /* Reset Micrel PHY */
+ clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
+ setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
}
-#endif
-#ifdef CONFIG_SMP
- mpc85xx_smp_init();
-#endif
+ iounmap(bcsr_regs);
+}
-#ifdef CONFIG_SWIOTLB
- if (lmb_end_of_DRAM() > max) {
- ppc_swiotlb_enable = 1;
- set_pci_dma_ops(&swiotlb_dma_ops);
- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
- }
-#endif
+static void __init mpc85xx_mds_qe_init(void)
+{
+ struct device_node *np;
-#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe");
if (!np) {
np = of_find_node_by_name(NULL, "qe");
@@ -260,70 +286,7 @@ static void __init mpc85xx_mds_setup_arch(void)
par_io_of_config(ucc);
}
- if (bcsr_regs) {
- if (machine_is(mpc8568_mds)) {
-#define BCSR_UCC1_GETH_EN (0x1 << 7)
-#define BCSR_UCC2_GETH_EN (0x1 << 7)
-#define BCSR_UCC1_MODE_MSK (0x3 << 4)
-#define BCSR_UCC2_MODE_MSK (0x3 << 0)
-
- /* Turn off UCC1 & UCC2 */
- clrbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
- clrbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
-
- /* Mode is RGMII, all bits clear */
- clrbits8(&bcsr_regs[11], BCSR_UCC1_MODE_MSK |
- BCSR_UCC2_MODE_MSK);
-
- /* Turn UCC1 & UCC2 on */
- setbits8(&bcsr_regs[8], BCSR_UCC1_GETH_EN);
- setbits8(&bcsr_regs[9], BCSR_UCC2_GETH_EN);
- } else if (machine_is(mpc8569_mds)) {
-#define BCSR7_UCC12_GETHnRST (0x1 << 2)
-#define BCSR8_UEM_MARVELL_RST (0x1 << 1)
-#define BCSR_UCC_RGMII (0x1 << 6)
-#define BCSR_UCC_RTBI (0x1 << 5)
- /*
- * U-Boot mangles interrupt polarity for Marvell PHYs,
- * so reset built-in and UEM Marvell PHYs, this puts
- * the PHYs into their normal state.
- */
- clrbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
- setbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
-
- setbits8(&bcsr_regs[7], BCSR7_UCC12_GETHnRST);
- clrbits8(&bcsr_regs[8], BCSR8_UEM_MARVELL_RST);
-
- for (np = NULL; (np = of_find_compatible_node(np,
- "network",
- "ucc_geth")) != NULL;) {
- const unsigned int *prop;
- int ucc_num;
-
- prop = of_get_property(np, "cell-index", NULL);
- if (prop == NULL)
- continue;
-
- ucc_num = *prop - 1;
-
- prop = of_get_property(np, "phy-connection-type", NULL);
- if (prop == NULL)
- continue;
-
- if (strcmp("rtbi", (const char *)prop) == 0)
- clrsetbits_8(&bcsr_regs[7 + ucc_num],
- BCSR_UCC_RGMII, BCSR_UCC_RTBI);
- }
-
- } else if (machine_is(p1021_mds)) {
-#define BCSR11_ENET_MICRST (0x1 << 5)
- /* Reset Micrel PHY */
- clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
- setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
- }
-
- iounmap(bcsr_regs);
- }
+ mpc85xx_mds_reset_ucc_phys();
if (machine_is(p1021_mds)) {
#define MPC85xx_PMUXCR_OFFSET 0x60
@@ -358,7 +321,79 @@ static void __init mpc85xx_mds_setup_arch(void)
}
}
+}
+
+static void __init mpc85xx_mds_qeic_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+ if (!np) {
+ np = of_find_node_by_type(NULL, "qeic");
+ if (!np)
+ return;
+ }
+
+ if (machine_is(p1021_mds))
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ else
+ qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
+ of_node_put(np);
+}
+#else
+static void __init mpc85xx_publish_qe_devices(void) { }
+static void __init mpc85xx_mds_qe_init(void) { }
+static void __init mpc85xx_mds_qeic_init(void) { }
#endif /* CONFIG_QUICC_ENGINE */
+
+static void __init mpc85xx_mds_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+ struct pci_controller *hose;
+#endif
+ dma_addr_t max = 0xffffffff;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc85xx_mds_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+ for_each_node_by_type(np, "pci") {
+ if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+ of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
+ struct resource rsrc;
+ of_address_to_resource(np, 0, &rsrc);
+ if ((rsrc.start & 0xfffff) == 0x8000)
+ fsl_add_bridge(np, 1);
+ else
+ fsl_add_bridge(np, 0);
+
+ hose = pci_find_hose_for_OF_device(np);
+ max = min(max, hose->dma_window_base_cur +
+ hose->dma_window_size);
+ }
+ }
+#endif
+
+#ifdef CONFIG_SMP
+ mpc85xx_smp_init();
+#endif
+
+ mpc85xx_mds_qe_init();
+
+#ifdef CONFIG_SWIOTLB
+ if (lmb_end_of_DRAM() > max) {
+ ppc_swiotlb_enable = 1;
+ set_pci_dma_ops(&swiotlb_dma_ops);
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+ }
+#endif
}
@@ -465,28 +500,7 @@ static void __init mpc85xx_mds_pic_init(void)
of_node_put(np);
mpic_init(mpic);
-
-#ifdef CONFIG_QUICC_ENGINE
- np = of_find_compatible_node(NULL, NULL, "fsl,qe");
- if (!of_device_is_available(np)) {
- of_node_put(np);
- return;
- }
-
- np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
- if (!np) {
- np = of_find_node_by_type(NULL, "qeic");
- if (!np)
- return;
- }
-
- if (machine_is(p1021_mds))
- qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
- qe_ic_cascade_high_mpic);
- else
- qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
- of_node_put(np);
-#endif /* CONFIG_QUICC_ENGINE */
+ mpc85xx_mds_qeic_init();
}
static int __init mpc85xx_mds_probe(void)
--
1.7.0.5
^ permalink raw reply related
* [PATCH 2/3] powerpc/85xx: Fix booting for P1021MDS boards
From: Anton Vorontsov @ 2010-06-08 19:55 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
P1021 processors have no dedicated ROM to store the QE microcode,
so the fimrware is stored externally, and it is U-Boot responsibility
to load it. It might be that the board is booting without QE, e.g.
currently U-Boot doesn't support QE for P1021MDS boards, which means
that QE isn't initialized, and so the board hangs early at boot.
This patch fixes the issue by marking QE as disabled and checking the
state in the probing code. U-Boot should fixup the state if it
initialized the QE.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
arch/powerpc/boot/dts/p1021mds.dts | 1 +
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 43 +++++++++++++++++++++++++----
2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/boot/dts/p1021mds.dts b/arch/powerpc/boot/dts/p1021mds.dts
index 7fad2df..ad5b852 100644
--- a/arch/powerpc/boot/dts/p1021mds.dts
+++ b/arch/powerpc/boot/dts/p1021mds.dts
@@ -617,6 +617,7 @@
bus-frequency = <0>;
fsl,qe-num-riscs = <1>;
fsl,qe-num-snums = <28>;
+ status = "disabled"; /* no firmware loaded */
qeic: interrupt-controller@80 {
interrupt-controller;
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 35ab2b4..9dadcff 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -158,6 +158,29 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev)
extern void __init mpc85xx_smp_init(void);
#endif
+#ifdef CONFIG_QUICC_ENGINE
+static struct of_device_id mpc85xx_qe_ids[] __initdata = {
+ { .type = "qe", },
+ { .compatible = "fsl,qe", },
+ { },
+};
+
+static void __init mpc85xx_publish_qe_devices(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
+ of_platform_bus_probe(NULL, mpc85xx_qe_ids, NULL);
+}
+#else
+static void __init mpc85xx_publish_qe_devices(void) { }
+#endif /* CONFIG_QUICC_ENGINE */
+
static void __init mpc85xx_mds_setup_arch(void)
{
struct device_node *np;
@@ -218,6 +241,11 @@ static void __init mpc85xx_mds_setup_arch(void)
return;
}
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
qe_reset();
of_node_put(np);
@@ -369,8 +397,6 @@ static struct of_device_id mpc85xx_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
- { .type = "qe", },
- { .compatible = "fsl,qe", },
{ .compatible = "gianfar", },
{ .compatible = "fsl,rapidio-delta", },
{ .compatible = "fsl,mpc8548-guts", },
@@ -382,8 +408,6 @@ static struct of_device_id p1021_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
- { .type = "qe", },
- { .compatible = "fsl,qe", },
{ .compatible = "gianfar", },
{},
};
@@ -395,16 +419,16 @@ static int __init mpc85xx_publish_devices(void)
if (machine_is(mpc8569_mds))
simple_gpiochip_init("fsl,mpc8569mds-bcsr-gpio");
- /* Publish the QE devices */
of_platform_bus_probe(NULL, mpc85xx_ids, NULL);
+ mpc85xx_publish_qe_devices();
return 0;
}
static int __init p1021_publish_devices(void)
{
- /* Publish the QE devices */
of_platform_bus_probe(NULL, p1021_ids, NULL);
+ mpc85xx_publish_qe_devices();
return 0;
}
@@ -443,12 +467,19 @@ static void __init mpc85xx_mds_pic_init(void)
mpic_init(mpic);
#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ return;
+ }
+
np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
if (!np) {
np = of_find_node_by_type(NULL, "qeic");
if (!np)
return;
}
+
if (machine_is(p1021_mds))
qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
qe_ic_cascade_high_mpic);
--
1.7.0.5
^ permalink raw reply related
* [PATCH 1/3] powerpc/85xx: Fix SWIOTLB initalization for MPC85xxMDS boards
From: Anton Vorontsov @ 2010-06-08 19:55 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev
The code inside '#ifdef CONFIG_QUICC_ENGINE' makes the
mpc85xx_mds_setup_arch() return early if no QE nodes present,
and so SWIOTLB is never initialized.
This patch fixes the issue by moving SWIOTLB code above
QE.
Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
arch/powerpc/platforms/85xx/mpc85xx_mds.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 8fe87fc..35ab2b4 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -202,6 +202,14 @@ static void __init mpc85xx_mds_setup_arch(void)
mpc85xx_smp_init();
#endif
+#ifdef CONFIG_SWIOTLB
+ if (lmb_end_of_DRAM() > max) {
+ ppc_swiotlb_enable = 1;
+ set_pci_dma_ops(&swiotlb_dma_ops);
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+ }
+#endif
+
#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe");
if (!np) {
@@ -323,14 +331,6 @@ static void __init mpc85xx_mds_setup_arch(void)
}
#endif /* CONFIG_QUICC_ENGINE */
-
-#ifdef CONFIG_SWIOTLB
- if (lmb_end_of_DRAM() > max) {
- ppc_swiotlb_enable = 1;
- set_pci_dma_ops(&swiotlb_dma_ops);
- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
- }
-#endif
}
--
1.7.0.5
^ permalink raw reply related
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-08 19:48 UTC (permalink / raw)
To: Grant Likely
Cc: sfr, monstr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <AANLkTinHH-YhdWpH60Z2BYsiEjzLb_imrk6KUmQRH07P@mail.gmail.com>
On Tue, Jun 08, 2010 at 12:41:47PM -0600, Grant Likely wrote:
[...]
> >> This is a common pattern.
> >
> > This can't be true because it produces ugly casts and fragile
> > code all over the place -- which is exactly what everybody
> > tries to avoid in the kernel.
>
> Fragile? How? &var[1] *always* gives you a pointer to the first
> address after a structure. If the structure changes, then so does the
> offset. Heck, if the type of 'var' changes, then the offset changes
> in kind too. If anything, I should have also used sizeof(*res) in the
> kzalloc call so that the allocated size is protected against a type
> change to 'res' too.
You just introduced an unnamed structure of device + resources,
it isn't declared anywhere but in the code itself (either via
&foo[1] or buf + sizeof(*foo)).
You're not the only one who hacks (or at least have to
understand) the OF stuff, so let's try keep this stuff
readable?
I told you several ways of how to improve the code (based on
the ideas from drivers/base/, so the ideas aren't even mine,
fwiw).
> If you prefer, I can move the dev->resource assignment to immediately
> after the kzalloc to keep everything contained within 4 lines of each
> other.
Sure, that would be better, but I already said what would I
really prefer, i.e.
- A dedicated allocation;
- Or, at least, the same thing as drivers/base/platform.c does:
platform_object { platform_device; name[1]; };
> > But I heard of no such pattern for 'struct device + struct
> > resources' allocation without even some kind of _priv struct,
> > which is surely something new, and ugly.
>
> git grep '\*).*&[a-z1-9_]*\[1\]'
Ugh? This produces a lot of false positives. But OK, let's run it.
~/linux-2.6$ git grep '\*).*&[a-z1-9_]*\[1\]' | wc -l
164
^^^ Now let's presume that half of it (and not just a few hits)
is the ugly hacks that we're talking about. Then compare:
~/linux-2.6$ git grep 'struct.*_priv' | wc -l
22448
^^^ this is a common pattern.
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-08 18:41 UTC (permalink / raw)
To: Anton Vorontsov
Cc: sfr, monstr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <20100608164645.GA15216@oksana.dev.rtsoft.ru>
On Tue, Jun 8, 2010 at 10:46 AM, Anton Vorontsov <cbouatmailru@gmail.com> w=
rote:
> On Tue, Jun 08, 2010 at 10:02:49AM -0600, Grant Likely wrote:
>> On Tue, Jun 8, 2010 at 9:57 AM, Anton Vorontsov <cbouatmailru@gmail.com>=
wrote:
>> > On Tue, Jun 08, 2010 at 08:26:43AM -0600, Grant Likely wrote:
>> > [...]
>> >> + =A0 =A0 dev =3D kzalloc(sizeof(*dev) + (sizeof(struct resource) * i=
), GFP_KERNEL);
>> >> =A0 =A0 =A0 if (!dev)
>> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> >> -
>> >> =A0 =A0 =A0 dev->dev.of_node =3D of_node_get(np);
>> >> =A0 =A0 =A0 dev->dev.dma_mask =3D &dev->archdata.dma_mask;
>> >> =A0 =A0 =A0 dev->dev.parent =3D parent;
>> >> =A0 =A0 =A0 dev->dev.release =3D of_release_dev;
>> >>
>> >> + =A0 =A0 /* Populate the resource table */
>> >> + =A0 =A0 if (num_irq || num_reg) {
>> >> + =A0 =A0 =A0 =A0 =A0 =A0 dev->resource =3D (void*)&dev[1];
>> >
>> > This is ugly. Why not allocate the memory specifically for
>> > dev->resource? Is this because you plan to get rid of
>> > of_release_dev(), and the generic release_dev() won't
>> > know if it should free the dev->resource? There must
>> > be a better way to handle this.
>>
>> Allocating in one big block means less potential memory fragmentation,
>> and the kernel can free it all at once.
>
> Are there any numbers of saved amount of memory so that we
> could compare?
>
> The "less memory fragmentation" is indeed potential, but
> introduction of obscure code is going on now at this precise
> moment.
It's not obscure. It's smaller and simpler code with fewer error paths.
>> This is a common pattern.
>
> This can't be true because it produces ugly casts and fragile
> code all over the place -- which is exactly what everybody
> tries to avoid in the kernel.
Fragile? How? &var[1] *always* gives you a pointer to the first
address after a structure. If the structure changes, then so does the
offset. Heck, if the type of 'var' changes, then the offset changes
in kind too. If anything, I should have also used sizeof(*res) in the
kzalloc call so that the allocated size is protected against a type
change to 'res' too.
If you prefer, I can move the dev->resource assignment to immediately
after the kzalloc to keep everything contained within 4 lines of each
other.
> Such a pattern is common when a driver allocates e.g. tx and rx
> buffers (of the same type) together, and then split the buffer
> into two pointers.
tx & rx buffers are different because they must be DMAable. That
imposes alignment requirements with kzalloc() guarantees.
> But I heard of no such pattern for 'struct device + struct
> resources' allocation without even some kind of _priv struct,
> which is surely something new, and ugly.
git grep '\*).*&[a-z1-9_]*\[1\]'
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH 0/2] mpc5200 ac97 gpio reset
From: Eric Millbrandt @ 2010-06-08 16:46 UTC (permalink / raw)
To: Grant Likely; +Cc: Mark Brown, linuxppc-dev
These patches reimplement the reset fuction in the ac97 to use gpio pins
instead of using the mpc5200 ac97 reset functionality in the psc. This
avoids a problem in which attached ac97 devices go into "test" mode appear
unresponsive.
These patches were tested on a pcm030 baseboard and on custom hardware with
a wm9715 audio codec/touchscreen controller.
Eric Millbrandt
---
Eric Millbrandt (2):
powerpc/5200: Export port-config
sound/soc: mpc5200_psc_ac97: Use gpio pins for cold reset.
arch/powerpc/boot/dts/lite5200.dts | 3 +
arch/powerpc/boot/dts/lite5200b.dts | 3 +
arch/powerpc/boot/dts/pcm030.dts | 3 +
arch/powerpc/boot/dts/pcm032.dts | 3 +
arch/powerpc/include/asm/mpc52xx.h | 2 +
arch/powerpc/platforms/52xx/mpc52xx_common.c | 61 +++++++++++++++++++
sound/soc/fsl/mpc5200_dma.h | 5 ++
sound/soc/fsl/mpc5200_psc_ac97.c | 83 ++++++++++++++++++++++=
++-
8 files changed, 159 insertions(+), 4 deletions(-)
-DISCLAIMER: an automatically appended disclaimer may follow. By posting-
-to a public e-mail mailing list I hereby grant permission to distribute-
-and copy this message.-
This e-mail and the information, including any attachments, it contains are=
intended to be a confidential communication only to the person or entity t=
o whom it is addressed and may contain information that is privileged. If t=
he reader of this message is not the intended recipient, you are hereby not=
ified that any dissemination, distribution or copying of this communication=
is strictly prohibited. If you have received this communication in error, =
please immediately notify the sender and destroy the original message.
Thank you.
Please consider the environment before printing this email.
^ permalink raw reply
* [PATCH 1/2] powerpc/5200: Export port-config
From: Eric Millbrandt @ 2010-06-08 16:46 UTC (permalink / raw)
To: Grant Likely; +Cc: Mark Brown, linuxppc-dev, Eric Millbrandt
In-Reply-To: <1276015562-28928-1-git-send-email-emillbrandt@dekaresearch.com>
Allow device drivers to safely modify port-config. This allows device driv=
ers
access to gpio pins to manually bit-bang slave devices.
Signed-off-by: Eric Millbrandt <emillbrandt@dekaresearch.com>
---
arch/powerpc/include/asm/mpc52xx.h | 2 +
arch/powerpc/platforms/52xx/mpc52xx_common.c | 61 ++++++++++++++++++++++=
++++
2 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/=
mpc52xx.h
index b664ce7..ebc5a3b 100644
--- a/arch/powerpc/include/asm/mpc52xx.h
+++ b/arch/powerpc/include/asm/mpc52xx.h
@@ -274,7 +274,9 @@ extern void mpc52xx_declare_of_platform_devices(void);
extern void mpc52xx_map_common_devices(void);
extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv);
extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node);
+extern unsigned int mpc52xx_read_port_config(void);
extern void mpc52xx_restart(char *cmd);
+extern int mpc52xx_write_port_config(u32 mux, int operation);
/* mpc52xx_gpt.c */
struct mpc52xx_gpt_priv;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/pl=
atforms/52xx/mpc52xx_common.c
index a46bad0..77c685a 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -37,6 +37,11 @@ static struct of_device_id mpc52xx_bus_ids[] __initdata =
=3D {
{}
};
+static struct of_device_id mpc52xx_gpio_simple[] =3D {
+ { .compatible =3D "fsl,mpc5200-gpio", },
+ {}
+};
+
/*
* This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restar=
t().
* Permanent mapping is required because mpc52xx_restart() can be called
@@ -82,6 +87,15 @@ mpc5200_setup_xlb_arbiter(void)
iounmap(xlb);
}
+/*
+ * This variable is mapped in mpc52xx_write_port_config() and
+ * mpc52xx_read_port_config(). Permanent mapping is required because
+ * mpc52xx_map_and_lock_port_config() can be called from interrupt context
+ * while node mapping (which calls ioremap()) cannot be used at such point=
.
+ */
+static DEFINE_SPINLOCK(mpc52xx_port_config_lock);
+static u32 __iomem *port_config;
+
/**
* mpc52xx_declare_of_platform_devices: register internal devices and chil=
dren
* of the localplus bus to the of_plat=
form
@@ -117,6 +131,7 @@ void __init
mpc52xx_map_common_devices(void)
{
struct device_node *np;
+ const u32 *regaddr;
/* mpc52xx_wdt is mapped here and used in mpc52xx_restart,
* possibly from a interrupt context. wdt is only implement
@@ -135,6 +150,13 @@ mpc52xx_map_common_devices(void)
np =3D of_find_matching_node(NULL, mpc52xx_cdm_ids);
mpc52xx_cdm =3D of_iomap(np, 0);
of_node_put(np);
+
+ /* port_config register */
+ np =3D of_find_matching_node(NULL, mpc52xx_gpio_simple);
+ regaddr =3D of_get_address(np, 0, NULL, NULL);
+ port_config =3D ioremap((u32) of_translate_address(np, regaddr), 0x=
4);
+
+ of_node_put(np);
}
/**
@@ -233,3 +255,42 @@ mpc52xx_restart(char *cmd)
while (1);
}
+
+/**
+ * mpc52xx_write_port_config: Allow mutually exclusive access to the
+ * port_config register
+ *
+ * @newmux: value to write to port_config
+ * @operation: set to 0 for | or 1 for &
+ */
+int mpc52xx_write_port_config(u32 newmux, int operation)
+{
+ unsigned long flags;
+ u32 mux;
+
+ if (!port_config)
+ return -ENODEV;
+
+ spin_lock_irqsave(&mpc52xx_port_config_lock, flags);
+ mux =3D in_be32(port_config);
+ if (operation)
+ out_be32(port_config, mux & newmux);
+ else
+ out_be32(port_config, mux | newmux);
+ spin_unlock_irqrestore(&mpc52xx_port_config_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpc52xx_write_port_config);
+
+/**
+ * mpc52xx_read_port_config: Return the value of port_config
+ */
+unsigned int mpc52xx_read_port_config(void)
+{
+ if (!port_config)
+ return -ENODEV;
+
+ return in_be32(port_config);
+}
+EXPORT_SYMBOL(mpc52xx_read_port_config);
--
1.6.3.1
This e-mail and the information, including any attachments, it contains are=
intended to be a confidential communication only to the person or entity t=
o whom it is addressed and may contain information that is privileged. If t=
he reader of this message is not the intended recipient, you are hereby not=
ified that any dissemination, distribution or copying of this communication=
is strictly prohibited. If you have received this communication in error, =
please immediately notify the sender and destroy the original message.
Thank you.
Please consider the environment before printing this email.
^ permalink raw reply related
* [PATCH 2/2] sound/soc: mpc5200_psc_ac97: Use gpio pins for cold reset.
From: Eric Millbrandt @ 2010-06-08 16:46 UTC (permalink / raw)
To: Grant Likely; +Cc: Mark Brown, linuxppc-dev, Eric Millbrandt
In-Reply-To: <1276015562-28928-2-git-send-email-emillbrandt@dekaresearch.com>
The implementation of the ac97 "cold" reset is flawed. If the sync and
output lines are high when reset is asserted the attached ac97 device
may go into test mode. Avoid this by reconfiguring the psc to gpio mode
and generating the reset manually.
Signed-off-by: Eric Millbrandt <emillbrandt@dekaresearch.com>
---
arch/powerpc/boot/dts/lite5200.dts | 3 +
arch/powerpc/boot/dts/lite5200b.dts | 3 +
arch/powerpc/boot/dts/pcm030.dts | 3 +
arch/powerpc/boot/dts/pcm032.dts | 3 +
sound/soc/fsl/mpc5200_dma.h | 5 ++
sound/soc/fsl/mpc5200_psc_ac97.c | 83 +++++++++++++++++++++++++++++++=
++--
6 files changed, 96 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lit=
e5200.dts
index 82ff2b1..cb4e49b 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -180,6 +180,9 @@
// compatible =3D "fsl,mpc5200-psc-ac97";
// cell-index =3D <1>;
// reg =3D <0x2200 0x100>;
+ // gpios =3D <&gpio 7 0 /* AC97_1_RES */
+ // &gpio_simple 29 0 /* AC97_1_SYNC */
+ // &gpio_simple 31 0>; /* AC97_1_SDATA_OUT=
*/
// interrupts =3D <2 2 0>;
//};
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/li=
te5200b.dts
index e45a63b..1fb0ac7 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -184,6 +184,9 @@
// compatible =3D "fsl,mpc5200b-psc-ac97","fsl,mpc5200=
-psc-ac97";
// cell-index =3D <1>;
// reg =3D <0x2200 0x100>;
+ // gpios =3D <&gpio 7 0 /* AC97_1_RES */
+ // &gpio_simple 29 0 /* AC97_1_SYNC */
+ // &gpio_simple 31 0>; /* AC97_1_SDATA_OUT=
*/
// interrupts =3D <2 2 0>;
//};
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm03=
0.dts
index 8a4ec30..0085e0f 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -189,6 +189,9 @@
compatible =3D "mpc5200b-psc-ac97","fsl,mpc5200b-ps=
c-ac97";
cell-index =3D <0>;
reg =3D <0x2000 0x100>;
+ gpios =3D <&gpio 7 0 /* AC97_1_RES */
+ &gpio_simple 29 0 /* AC97_1_SYNC */
+ &gpio_simple 31 0>; /* AC97_1_SDATA_OUT=
*/
interrupts =3D <2 1 0>;
};
diff --git a/arch/powerpc/boot/dts/pcm032.dts b/arch/powerpc/boot/dts/pcm03=
2.dts
index 85d857a..76f86d3 100644
--- a/arch/powerpc/boot/dts/pcm032.dts
+++ b/arch/powerpc/boot/dts/pcm032.dts
@@ -189,6 +189,9 @@
compatible =3D "fsl,mpc5200b-psc-ac97","fsl,mpc5200=
-psc-ac97";
cell-index =3D <0>;
reg =3D <0x2000 0x100>;
+ gpios =3D <&gpio 7 0 /* AC97_1_RES */
+ &gpio_simple 29 0 /* AC97_1_SYNC */
+ &gpio_simple 31 0>; /* AC97_1_SDATA_OUT=
*/
interrupts =3D <2 1 0>;
};
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index 22208b3..9fb0248 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -61,6 +61,11 @@ struct psc_dma {
int id;
unsigned int slots;
+ /* gpio pins locations for cold reset */
+ int reset_gpio;
+ int sync_gpio;
+ int out_gpio;
+
/* per-stream data */
struct psc_dma_stream playback;
struct psc_dma_stream capture;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_a=
c97.c
index e2ee220..bbbf860 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -9,8 +9,10 @@
* published by the Free Software Foundation.
*/
+#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
@@ -20,12 +22,17 @@
#include <asm/time.h>
#include <asm/delay.h>
+#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
#include "mpc5200_dma.h"
#include "mpc5200_psc_ac97.h"
#define DRV_NAME "mpc5200-psc-ac97"
+#define MPC52xx_GPIO_PSC1_MASK 0x7
+#define MPC52xx_GPIO_PSC2_MASK (0x7<<4)
+#define MPC52xx_AC97_PSC1 0x2
+#define MPC52xx_AC97_PSC2 (0x2<<4)
/* ALSA only supports a single AC97 device so static is recommend here */
static struct psc_dma *psc_dma;
@@ -100,19 +107,69 @@ static void psc_ac97_warm_reset(struct snd_ac97 *ac97=
)
{
struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
+ mutex_lock(&psc_dma->mutex);
+
out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
udelay(3);
out_be32(®s->sicr, psc_dma->sicr);
+
+ mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
+ u32 gpio_mux;
+
+ mutex_lock(&psc_dma->mutex);
+
+ /* Reconfigure pin-muxing to gpio */
+ switch (psc_dma->id) {
+ case 0:
+ gpio_mux =3D MPC52xx_GPIO_PSC1_MASK; break;
+ case 1:
+ gpio_mux =3D MPC52xx_GPIO_PSC2_MASK; break;
+ default:
+ dev_err(psc_dma->dev,
+ "Unable to determine PSC, no cold-reset will be "
+ "performed\n");
+ return;
+ }
+
+ dev_err(psc_dma->dev, "cold reset\n");
+ mpc52xx_write_port_config(~gpio_mux, 1);
+
+ /* Assert cold reset */
+ gpio_direction_output(psc_dma->sync_gpio, 0);
+ gpio_direction_output(psc_dma->out_gpio, 0);
+ gpio_direction_output(psc_dma->reset_gpio, 0);
+
+ /* Notify the PSC that a cold reset is occurring */
+ out_be32(®s->sicr, 0);
+ udelay(2);
+
+ /* Deassert reset */
+ gpio_direction_output(psc_dma->reset_gpio, 1);
+ msleep(1);
+
+ /* Restore pin-muxing */
+ switch (psc_dma->id) {
+ case 0:
+ gpio_mux =3D MPC52xx_AC97_PSC1; break;
+ case 1:
+ gpio_mux =3D MPC52xx_AC97_PSC2; break;
+ default:
+ return;
+ }
+
+ mpc52xx_write_port_config(gpio_mux, 0);
+
+ /* Restore the serial interface mode to AC97 */
+ out_be32(®s->sicr, psc_dma->sicr);
+ out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE=
);
+
+ mutex_unlock(&psc_dma->mutex);
- /* Do a cold reset */
- out_8(®s->op1, MPC52xx_PSC_OP_RES);
- udelay(10);
- out_8(®s->op0, MPC52xx_PSC_OP_RES);
msleep(1);
psc_ac97_warm_reset(ac97);
}
@@ -287,6 +344,24 @@ static int __devinit psc_ac97_of_probe(struct of_devic=
e *op,
regs =3D psc_dma->psc_regs;
ac97.private_data =3D psc_dma;
+ psc_dma->reset_gpio =3D of_get_gpio_flags(op->node, 0, NULL);
+ psc_dma->sync_gpio =3D of_get_gpio_flags(op->node, 1, NULL);
+ psc_dma->out_gpio =3D of_get_gpio_flags(op->node, 2, NULL);
+ if ((psc_dma->reset_gpio < 0) ||
+ (psc_dma->sync_gpio < 0) ||
+ (psc_dma->out_gpio < 0)) {
+ dev_err(&op->dev, "error: cannot get GPIO pins; "
+ "reset=3D%i sync=3D%i out=3D%i\n",
+ psc_dma->reset_gpio,
+ psc_dma->sync_gpio,
+ psc_dma->out_gpio);
+ return -ENODEV;
+ }
+
+ gpio_request(psc_dma->reset_gpio, "psc_dma-reset");
+ gpio_request(psc_dma->sync_gpio, "psc_dma-sync");
+ gpio_request(psc_dma->out_gpio, "psc_dma-out");
+
for (i =3D 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
psc_ac97_dai[i].private_data =3D psc_dma;
--
1.6.3.1
This e-mail and the information, including any attachments, it contains are=
intended to be a confidential communication only to the person or entity t=
o whom it is addressed and may contain information that is privileged. If t=
he reader of this message is not the intended recipient, you are hereby not=
ified that any dissemination, distribution or copying of this communication=
is strictly prohibited. If you have received this communication in error, =
please immediately notify the sender and destroy the original message.
Thank you.
Please consider the environment before printing this email.
^ permalink raw reply related
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-08 16:46 UTC (permalink / raw)
To: Grant Likely
Cc: sfr, monstr, devicetree-discuss, microblaze-uclinux, jeremy.kerr,
linuxppc-dev
In-Reply-To: <AANLkTinZT4z93SWxjce5oRZzmaQHtVnO96zsXO9OX2UZ@mail.gmail.com>
On Tue, Jun 08, 2010 at 10:02:49AM -0600, Grant Likely wrote:
> On Tue, Jun 8, 2010 at 9:57 AM, Anton Vorontsov <cbouatmailru@gmail.com> wrote:
> > On Tue, Jun 08, 2010 at 08:26:43AM -0600, Grant Likely wrote:
> > [...]
> >> + dev = kzalloc(sizeof(*dev) + (sizeof(struct resource) * i), GFP_KERNEL);
> >> if (!dev)
> >> return NULL;
> >> -
> >> dev->dev.of_node = of_node_get(np);
> >> dev->dev.dma_mask = &dev->archdata.dma_mask;
> >> dev->dev.parent = parent;
> >> dev->dev.release = of_release_dev;
> >>
> >> + /* Populate the resource table */
> >> + if (num_irq || num_reg) {
> >> + dev->resource = (void*)&dev[1];
> >
> > This is ugly. Why not allocate the memory specifically for
> > dev->resource? Is this because you plan to get rid of
> > of_release_dev(), and the generic release_dev() won't
> > know if it should free the dev->resource? There must
> > be a better way to handle this.
>
> Allocating in one big block means less potential memory fragmentation,
> and the kernel can free it all at once.
Are there any numbers of saved amount of memory so that we
could compare?
The "less memory fragmentation" is indeed potential, but
introduction of obscure code is going on now at this precise
moment.
> This is a common pattern.
This can't be true because it produces ugly casts and fragile
code all over the place -- which is exactly what everybody
tries to avoid in the kernel.
Such a pattern is common when a driver allocates e.g. tx and rx
buffers (of the same type) together, and then split the buffer
into two pointers.
But I heard of no such pattern for 'struct device + struct
resources' allocation without even some kind of _priv struct,
which is surely something new, and ugly.
If you really want to avoid (an unproven) memory fragmentation,
you could do:
struct of_device_with_resources {
struct device dev;
struct resource resourses[0];
};
This at least will get rid of the casts and incomprehensible
"dev->resource = (void*)&dev[1];" construction.
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-08 16:02 UTC (permalink / raw)
To: Anton Vorontsov
Cc: ben, sfr, monstr, microblaze-uclinux, devicetree-discuss,
jeremy.kerr, linuxppc-dev
In-Reply-To: <20100608155702.GA5419@oksana.dev.rtsoft.ru>
On Tue, Jun 8, 2010 at 9:57 AM, Anton Vorontsov <cbouatmailru@gmail.com> wr=
ote:
> On Tue, Jun 08, 2010 at 08:26:43AM -0600, Grant Likely wrote:
> [...]
>> + =A0 =A0 dev =3D kzalloc(sizeof(*dev) + (sizeof(struct resource) * i), =
GFP_KERNEL);
>> =A0 =A0 =A0 if (!dev)
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
>> -
>> =A0 =A0 =A0 dev->dev.of_node =3D of_node_get(np);
>> =A0 =A0 =A0 dev->dev.dma_mask =3D &dev->archdata.dma_mask;
>> =A0 =A0 =A0 dev->dev.parent =3D parent;
>> =A0 =A0 =A0 dev->dev.release =3D of_release_dev;
>>
>> + =A0 =A0 /* Populate the resource table */
>> + =A0 =A0 if (num_irq || num_reg) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 dev->resource =3D (void*)&dev[1];
>
> This is ugly. Why not allocate the memory specifically for
> dev->resource? Is this because you plan to get rid of
> of_release_dev(), and the generic release_dev() won't
> know if it should free the dev->resource? There must
> be a better way to handle this.
Allocating in one big block means less potential memory fragmentation,
and the kernel can free it all at once. This is a common pattern.
> p.s.
>
> Just wonder what happened to of_gpio stuff? You blocked it
> in 2.6.34 for no reason saying "I'll pick it into my OF
> tree before the 2.6.35 merge window" and it's 2.6.36 merge
> window quite soon.
It's in my test-devicetree branch. I'll be posting for 2nd review in
the next few days and then adding to my devicetree-next branch
probably before the end of the week.
g.
^ permalink raw reply
* Re: [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Anton Vorontsov @ 2010-06-08 15:57 UTC (permalink / raw)
To: Grant Likely
Cc: ben, sfr, monstr, microblaze-uclinux, devicetree-discuss,
jeremy.kerr, linuxppc-dev
In-Reply-To: <20100608142643.26088.61366.stgit@angua>
On Tue, Jun 08, 2010 at 08:26:43AM -0600, Grant Likely wrote:
[...]
> + dev = kzalloc(sizeof(*dev) + (sizeof(struct resource) * i), GFP_KERNEL);
> if (!dev)
> return NULL;
> -
> dev->dev.of_node = of_node_get(np);
> dev->dev.dma_mask = &dev->archdata.dma_mask;
> dev->dev.parent = parent;
> dev->dev.release = of_release_dev;
>
> + /* Populate the resource table */
> + if (num_irq || num_reg) {
> + dev->resource = (void*)&dev[1];
This is ugly. Why not allocate the memory specifically for
dev->resource? Is this because you plan to get rid of
of_release_dev(), and the generic release_dev() won't
know if it should free the dev->resource? There must
be a better way to handle this.
p.s.
[Two Minutes Hate for Grant.]
Just wonder what happened to of_gpio stuff? You blocked it
in 2.6.34 for no reason saying "I'll pick it into my OF
tree before the 2.6.35 merge window" and it's 2.6.36 merge
window quite soon.
It's still in origin/test-devicetree, which is obviously
not -next. What is your plan now?
Thanks,
> + dev->num_resources = num_reg + num_irq;
> + res = dev->resource;
> + for (i = 0; i < num_reg; i++, res++) {
> + rc = of_address_to_resource(np, i, res);
> + WARN_ON(rc);
> + }
> + for (i = 0; i < num_irq; i++, res++) {
> + rc = of_irq_to_resource(np, i, res);
> + WARN_ON(rc == NO_IRQ);
> + }
> + }
> +
> if (bus_id)
> dev_set_name(&dev->dev, "%s", bus_id);
> else
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* Re: [PATCH] kexec, ppc64: Wait for online/possible CPUs only.
From: Michael Ellerman @ 2010-06-08 15:48 UTC (permalink / raw)
To: Matt Evans; +Cc: linuxppc-dev, kexec, Milton Miller
In-Reply-To: <4C0DF36A.3080401@ozlabs.org>
[-- Attachment #1: Type: text/plain, Size: 1045 bytes --]
On Tue, 2010-06-08 at 17:38 +1000, Matt Evans wrote:
> kexec_perpare_cpus_wait() iterates i through NR_CPUS to check
> paca[i].kexec_state of each to make sure they have quiesced.
> However now we have dynamic PACA allocation, paca[NR_CPUS] is not necessarily
> valid and we overrun the array; spurious "cpu is not possible, ignoring"
> errors result. This patch iterates for_each_online_cpu so stays
> within the bounds of paca[] -- and every CPU is now 'possible'.
>
> Signed-off-by: Matt Evans <matt@ozlabs.org>
Looks good ..
Cautiously-acked-by: Michael Ellerman <michael@ellerman.id.au>
> - if (!cpu_online(i)) {
> - /* Fixme: this can be spinning in
> - * pSeries_secondary_wait with a paca
> - * waiting for it to go online.
> - */
> - printk("kexec: cpu %d hw_cpu_id %d is not"
> - " online, ignoring\n",
> - i, paca[i].hw_cpu_id);
> - break;
> - }
I don't see how the state in the Fixme could ever happen, but maybe
Milton can seeing I think he wrote it?
cheers
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* [PATCH 3/5] of/address: Merge all of the bus translation code
From: Grant Likely @ 2010-06-08 14:10 UTC (permalink / raw)
Cc: Stephen Rothwell, Michal Simek, linuxppc-dev, microblaze-uclinux
In-Reply-To: <20100608140917.25879.67745.stgit@angua>
Microblaze and PowerPC share a large chunk of code for translating
OF device tree data into usable addresses. There aren't many differences
between the two, so merge the codebase wholesale rather than trying to
work out the independent bits.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: Michal Simek <monstr@monstr.eu>
CC: Wolfram Sang <w.sang@pengutronix.de>
CC: Stephen Rothwell <sfr@canb.auug.org.au>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: microblaze-uclinux@itee.uq.edu.au
CC: linuxppc-dev@ozlabs.org
---
arch/microblaze/include/asm/prom.h | 4
arch/microblaze/kernel/prom_parse.c | 489 ---------------------------------
arch/powerpc/include/asm/prom.h | 4
arch/powerpc/kernel/prom_parse.c | 515 -----------------------------------
drivers/of/address.c | 517 +++++++++++++++++++++++++++++++++++
include/linux/of_address.h | 4
6 files changed, 515 insertions(+), 1018 deletions(-)
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h
index 644fa32..35cb3de 100644
--- a/arch/microblaze/include/asm/prom.h
+++ b/arch/microblaze/include/asm/prom.h
@@ -52,10 +52,6 @@ extern void pci_create_OF_bus_map(void);
* OF address retreival & translation
*/
-/* Translate an OF address block into a CPU physical address
- */
-extern u64 of_translate_address(struct device_node *np, const u32 *addr);
-
/* Extract an address from a device, returns the region size and
* the address space flags too. The PCI version uses a BAR number
* instead of an absolute index
diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c
index 7cb5a98..1d610e6 100644
--- a/arch/microblaze/kernel/prom_parse.c
+++ b/arch/microblaze/kernel/prom_parse.c
@@ -10,213 +10,7 @@
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-#define PRu64 "%llx"
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS 4
-#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
- (ns) > 0)
-
-static struct of_bus *of_match_bus(struct device_node *np);
-
-/* Debug utility */
-#ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
-{
- printk(KERN_INFO "%s", s);
- while (na--)
- printk(KERN_INFO " %08x", *(addr++));
- printk(KERN_INFO "\n");
-}
-#else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
-#endif
-
-/* Callbacks for bus specific translators */
-struct of_bus {
- const char *name;
- const char *addresses;
- int (*match)(struct device_node *parent);
- void (*count_cells)(struct device_node *child,
- int *addrc, int *sizec);
- u64 (*map)(u32 *addr, const u32 *range,
- int na, int ns, int pna);
- int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(const u32 *addr);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = of_n_addr_cells(dev);
- if (sizec)
- *sizec = of_n_size_cells(dev);
-}
-
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
- int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- cp = of_read_number(range, na);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr, na);
-
- pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
- cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
-{
- u64 a = of_read_number(addr, na);
- memset(addr, 0, na * 4);
- a += offset;
- if (na > 1)
- addr[na - 2] = a >> 32;
- addr[na - 1] = a & 0xffffffffu;
-
- return 0;
-}
-
-static unsigned int of_bus_default_get_flags(const u32 *addr)
-{
- return IORESOURCE_MEM;
-}
-
#ifdef CONFIG_PCI
-/*
- * PCI bus specific translator
- */
-
-static int of_bus_pci_match(struct device_node *np)
-{
- /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
- return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
-}
-
-static void of_bus_pci_count_cells(struct device_node *np,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 3;
- if (sizec)
- *sizec = 2;
-}
-
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x03000000)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- switch ((w >> 24) & 0x03) {
- case 0x01:
- flags |= IORESOURCE_IO;
- break;
- case 0x02: /* 32 bits */
- case 0x03: /* 64 bits */
- flags |= IORESOURCE_MEM;
- break;
- }
- if (w & 0x40000000)
- flags |= IORESOURCE_PREFETCH;
- return flags;
-}
-
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci")) {
- of_node_put(parent);
- return NULL;
- }
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_pci_address);
-
-int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_pci_address(dev, bar, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
-
-static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
-{
- return (((pin - 1) + slot) % 4) + 1;
-}
-
int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
{
struct device_node *dn, *ppnode;
@@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
EXPORT_SYMBOL_GPL(of_irq_map_pci);
#endif /* CONFIG_PCI */
-/*
- * ISA bus specific translator
- */
-
-static int of_bus_isa_match(struct device_node *np)
-{
- return !strcmp(np->name, "isa");
-}
-
-static void of_bus_isa_count_cells(struct device_node *child,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 2;
- if (sizec)
- *sizec = 1;
-}
-
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x00000001)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- if (w & 1)
- flags |= IORESOURCE_IO;
- else
- flags |= IORESOURCE_MEM;
- return flags;
-}
-
-/*
- * Array of bus specific translators
- */
-
-static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
- /* PCI */
- {
- .name = "pci",
- .addresses = "assigned-addresses",
- .match = of_bus_pci_match,
- .count_cells = of_bus_pci_count_cells,
- .map = of_bus_pci_map,
- .translate = of_bus_pci_translate,
- .get_flags = of_bus_pci_get_flags,
- },
-#endif /* CONFIG_PCI */
- /* ISA */
- {
- .name = "isa",
- .addresses = "reg",
- .match = of_bus_isa_match,
- .count_cells = of_bus_isa_count_cells,
- .map = of_bus_isa_map,
- .translate = of_bus_isa_translate,
- .get_flags = of_bus_isa_get_flags,
- },
- /* Default */
- {
- .name = "default",
- .addresses = "reg",
- .match = NULL,
- .count_cells = of_bus_default_count_cells,
- .map = of_bus_default_map,
- .translate = of_bus_default_translate,
- .get_flags = of_bus_default_get_flags,
- },
-};
-
-static struct of_bus *of_match_bus(struct device_node *np)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(of_busses); i++)
- if (!of_busses[i].match || of_busses[i].match(np))
- return &of_busses[i];
- BUG();
- return NULL;
-}
-
-static int of_translate_one(struct device_node *parent, struct of_bus *bus,
- struct of_bus *pbus, u32 *addr,
- int na, int ns, int pna)
-{
- const u32 *ranges;
- unsigned int rlen;
- int rone;
- u64 offset = OF_BAD_ADDR;
-
- /* Normally, an absence of a "ranges" property means we are
- * crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
- * Unfortunately, while this is very clear in the spec, it's not
- * what Apple understood, and they do have things like /uni-n or
- * /ht nodes with no "ranges" property and a lot of perfectly
- * useable mapped devices below them. Thus we treat the absence of
- * "ranges" as equivalent to an empty "ranges" property which means
- * a 1:1 translation at that level. It's up to the caller not to try
- * to translate addresses that aren't supposed to be translated in
- * the first place. --BenH.
- */
- ranges = of_get_property(parent, "ranges", (int *) &rlen);
- if (ranges == NULL || rlen == 0) {
- offset = of_read_number(addr, na);
- memset(addr, 0, pna * 4);
- pr_debug("OF: no ranges, 1:1 translation\n");
- goto finish;
- }
-
- pr_debug("OF: walking ranges...\n");
-
- /* Now walk through the ranges */
- rlen /= 4;
- rone = na + pna + ns;
- for (; rlen >= rone; rlen -= rone, ranges += rone) {
- offset = bus->map(addr, ranges, na, ns, pna);
- if (offset != OF_BAD_ADDR)
- break;
- }
- if (offset == OF_BAD_ADDR) {
- pr_debug("OF: not found !\n");
- return 1;
- }
- memcpy(addr, ranges + na, 4 * pna);
-
- finish:
- of_dump_addr("OF: parent translation for:", addr, pna);
- pr_debug("OF: with offset: "PRu64"\n", offset);
-
- /* Translate it into parent bus space */
- return pbus->translate(addr, offset, pna);
-}
-
-/*
- * Translate an address from the device-tree into a CPU physical address,
- * this walks up the tree and applies the various bus mappings on the
- * way.
- *
- * Note: We consider that crossing any level with #size-cells == 0 to mean
- * that translation is impossible (that is we are not dealing with a value
- * that can be mapped to a cpu physical address). This is not really specified
- * that way, but this is traditionally the way IBM at least do things
- */
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
-{
- struct device_node *parent = NULL;
- struct of_bus *bus, *pbus;
- u32 addr[OF_MAX_ADDR_CELLS];
- int na, ns, pna, pns;
- u64 result = OF_BAD_ADDR;
-
- pr_debug("OF: ** translation for device %s **\n", dev->full_name);
-
- /* Increase refcount at current level */
- of_node_get(dev);
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- goto bail;
- bus = of_match_bus(parent);
-
- /* Cound address cells & copy address locally */
- bus->count_cells(dev, &na, &ns);
- if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- goto bail;
- }
- memcpy(addr, in_addr, na * 4);
-
- pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
- bus->name, na, ns, parent->full_name);
- of_dump_addr("OF: translating address:", addr, na);
-
- /* Translate */
- for (;;) {
- /* Switch to parent bus */
- of_node_put(dev);
- dev = parent;
- parent = of_get_parent(dev);
-
- /* If root, we have finished */
- if (parent == NULL) {
- pr_debug("OF: reached root node\n");
- result = of_read_number(addr, na);
- break;
- }
-
- /* Get new parent bus and counts */
- pbus = of_match_bus(parent);
- pbus->count_cells(dev, &pna, &pns);
- if (!OF_CHECK_COUNTS(pna, pns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- break;
- }
-
- pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
- pbus->name, pna, pns, parent->full_name);
-
- /* Apply bus translation */
- if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
- break;
-
- /* Complete the move up one level */
- na = pna;
- ns = pns;
- bus = pbus;
-
- of_dump_addr("OF: one level translation:", addr, na);
- }
- bail:
- of_node_put(parent);
- of_node_put(dev);
-
- return result;
-}
-EXPORT_SYMBOL(of_translate_address);
-
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, (int *) &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if (i == index) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_address);
-
void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
unsigned long *busno, unsigned long *phys, unsigned long *size)
{
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index e1c1bdd..8e1d0fe 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -45,10 +45,6 @@ extern void pci_create_OF_bus_map(void);
* OF address retreival & translation
*/
-/* Translate an OF address block into a CPU physical address
- */
-extern u64 of_translate_address(struct device_node *np, const u32 *addr);
-
/* Translate a DMA address from device space to CPU space */
extern u64 of_translate_dma_address(struct device_node *dev,
const u32 *in_addr);
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index a2ef129..64f2606 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -10,225 +10,7 @@
#include <asm/prom.h>
#include <asm/pci-bridge.h>
-#ifdef DEBUG
-#define DBG(fmt...) do { printk(fmt); } while(0)
-#else
-#define DBG(fmt...) do { } while(0)
-#endif
-
-#ifdef CONFIG_PPC64
-#define PRu64 "%lx"
-#else
-#define PRu64 "%llx"
-#endif
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS 4
-#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
- (ns) > 0)
-
-static struct of_bus *of_match_bus(struct device_node *np);
-
-/* Debug utility */
-#ifdef DEBUG
-static void of_dump_addr(const char *s, const u32 *addr, int na)
-{
- printk("%s", s);
- while(na--)
- printk(" %08x", *(addr++));
- printk("\n");
-}
-#else
-static void of_dump_addr(const char *s, const u32 *addr, int na) { }
-#endif
-
-
-/* Callbacks for bus specific translators */
-struct of_bus {
- const char *name;
- const char *addresses;
- int (*match)(struct device_node *parent);
- void (*count_cells)(struct device_node *child,
- int *addrc, int *sizec);
- u64 (*map)(u32 *addr, const u32 *range,
- int na, int ns, int pna);
- int (*translate)(u32 *addr, u64 offset, int na);
- unsigned int (*get_flags)(const u32 *addr);
-};
-
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = of_n_addr_cells(dev);
- if (sizec)
- *sizec = of_n_size_cells(dev);
-}
-
-static u64 of_bus_default_map(u32 *addr, const u32 *range,
- int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- cp = of_read_number(range, na);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr, na);
-
- DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
- cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_default_translate(u32 *addr, u64 offset, int na)
-{
- u64 a = of_read_number(addr, na);
- memset(addr, 0, na * 4);
- a += offset;
- if (na > 1)
- addr[na - 2] = a >> 32;
- addr[na - 1] = a & 0xffffffffu;
-
- return 0;
-}
-
-static unsigned int of_bus_default_get_flags(const u32 *addr)
-{
- return IORESOURCE_MEM;
-}
-
-
#ifdef CONFIG_PCI
-/*
- * PCI bus specific translator
- */
-
-static int of_bus_pci_match(struct device_node *np)
-{
- /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
- return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
-}
-
-static void of_bus_pci_count_cells(struct device_node *np,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 3;
- if (sizec)
- *sizec = 2;
-}
-
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- switch((w >> 24) & 0x03) {
- case 0x01:
- flags |= IORESOURCE_IO;
- break;
- case 0x02: /* 32 bits */
- case 0x03: /* 64 bits */
- flags |= IORESOURCE_MEM;
- break;
- }
- if (w & 0x40000000)
- flags |= IORESOURCE_PREFETCH;
- return flags;
-}
-
-static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
- unsigned int af, rf;
-
- af = of_bus_pci_get_flags(addr);
- rf = of_bus_pci_get_flags(range);
-
- /* Check address type match */
- if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- if (strcmp(bus->name, "pci")) {
- of_node_put(parent);
- return NULL;
- }
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_pci_address);
-
-int of_pci_address_to_resource(struct device_node *dev, int bar,
- struct resource *r)
-{
- const u32 *addrp;
- u64 size;
- unsigned int flags;
-
- addrp = of_get_pci_address(dev, bar, &size, &flags);
- if (addrp == NULL)
- return -EINVAL;
- return __of_address_to_resource(dev, addrp, size, flags, r);
-}
-EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
-
int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
{
struct device_node *dn, *ppnode;
@@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
EXPORT_SYMBOL_GPL(of_irq_map_pci);
#endif /* CONFIG_PCI */
-/*
- * ISA bus specific translator
- */
-
-static int of_bus_isa_match(struct device_node *np)
-{
- return !strcmp(np->name, "isa");
-}
-
-static void of_bus_isa_count_cells(struct device_node *child,
- int *addrc, int *sizec)
-{
- if (addrc)
- *addrc = 2;
- if (sizec)
- *sizec = 1;
-}
-
-static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
- u64 cp, s, da;
-
- /* Check address type match */
- if ((addr[0] ^ range[0]) & 0x00000001)
- return OF_BAD_ADDR;
-
- /* Read address values, skipping high cell */
- cp = of_read_number(range + 1, na - 1);
- s = of_read_number(range + na + pna, ns);
- da = of_read_number(addr + 1, na - 1);
-
- DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
-
- if (da < cp || da >= (cp + s))
- return OF_BAD_ADDR;
- return da - cp;
-}
-
-static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
-{
- return of_bus_default_translate(addr + 1, offset, na - 1);
-}
-
-static unsigned int of_bus_isa_get_flags(const u32 *addr)
-{
- unsigned int flags = 0;
- u32 w = addr[0];
-
- if (w & 1)
- flags |= IORESOURCE_IO;
- else
- flags |= IORESOURCE_MEM;
- return flags;
-}
-
-
-/*
- * Array of bus specific translators
- */
-
-static struct of_bus of_busses[] = {
-#ifdef CONFIG_PCI
- /* PCI */
- {
- .name = "pci",
- .addresses = "assigned-addresses",
- .match = of_bus_pci_match,
- .count_cells = of_bus_pci_count_cells,
- .map = of_bus_pci_map,
- .translate = of_bus_pci_translate,
- .get_flags = of_bus_pci_get_flags,
- },
-#endif /* CONFIG_PCI */
- /* ISA */
- {
- .name = "isa",
- .addresses = "reg",
- .match = of_bus_isa_match,
- .count_cells = of_bus_isa_count_cells,
- .map = of_bus_isa_map,
- .translate = of_bus_isa_translate,
- .get_flags = of_bus_isa_get_flags,
- },
- /* Default */
- {
- .name = "default",
- .addresses = "reg",
- .match = NULL,
- .count_cells = of_bus_default_count_cells,
- .map = of_bus_default_map,
- .translate = of_bus_default_translate,
- .get_flags = of_bus_default_get_flags,
- },
-};
-
-static struct of_bus *of_match_bus(struct device_node *np)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
- if (!of_busses[i].match || of_busses[i].match(np))
- return &of_busses[i];
- BUG();
- return NULL;
-}
-
-static int of_translate_one(struct device_node *parent, struct of_bus *bus,
- struct of_bus *pbus, u32 *addr,
- int na, int ns, int pna, const char *rprop)
-{
- const u32 *ranges;
- unsigned int rlen;
- int rone;
- u64 offset = OF_BAD_ADDR;
-
- /* Normally, an absence of a "ranges" property means we are
- * crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
- * Unfortunately, while this is very clear in the spec, it's not
- * what Apple understood, and they do have things like /uni-n or
- * /ht nodes with no "ranges" property and a lot of perfectly
- * useable mapped devices below them. Thus we treat the absence of
- * "ranges" as equivalent to an empty "ranges" property which means
- * a 1:1 translation at that level. It's up to the caller not to try
- * to translate addresses that aren't supposed to be translated in
- * the first place. --BenH.
- */
- ranges = of_get_property(parent, rprop, &rlen);
- if (ranges == NULL || rlen == 0) {
- offset = of_read_number(addr, na);
- memset(addr, 0, pna * 4);
- DBG("OF: no ranges, 1:1 translation\n");
- goto finish;
- }
-
- DBG("OF: walking ranges...\n");
-
- /* Now walk through the ranges */
- rlen /= 4;
- rone = na + pna + ns;
- for (; rlen >= rone; rlen -= rone, ranges += rone) {
- offset = bus->map(addr, ranges, na, ns, pna);
- if (offset != OF_BAD_ADDR)
- break;
- }
- if (offset == OF_BAD_ADDR) {
- DBG("OF: not found !\n");
- return 1;
- }
- memcpy(addr, ranges + na, 4 * pna);
-
- finish:
- of_dump_addr("OF: parent translation for:", addr, pna);
- DBG("OF: with offset: "PRu64"\n", offset);
-
- /* Translate it into parent bus space */
- return pbus->translate(addr, offset, pna);
-}
-
-
-/*
- * Translate an address from the device-tree into a CPU physical address,
- * this walks up the tree and applies the various bus mappings on the
- * way.
- *
- * Note: We consider that crossing any level with #size-cells == 0 to mean
- * that translation is impossible (that is we are not dealing with a value
- * that can be mapped to a cpu physical address). This is not really specified
- * that way, but this is traditionally the way IBM at least do things
- */
-u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
- const char *rprop)
-{
- struct device_node *parent = NULL;
- struct of_bus *bus, *pbus;
- u32 addr[OF_MAX_ADDR_CELLS];
- int na, ns, pna, pns;
- u64 result = OF_BAD_ADDR;
-
- DBG("OF: ** translation for device %s **\n", dev->full_name);
-
- /* Increase refcount at current level */
- of_node_get(dev);
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- goto bail;
- bus = of_match_bus(parent);
-
- /* Cound address cells & copy address locally */
- bus->count_cells(dev, &na, &ns);
- if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- goto bail;
- }
- memcpy(addr, in_addr, na * 4);
-
- DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
- bus->name, na, ns, parent->full_name);
- of_dump_addr("OF: translating address:", addr, na);
-
- /* Translate */
- for (;;) {
- /* Switch to parent bus */
- of_node_put(dev);
- dev = parent;
- parent = of_get_parent(dev);
-
- /* If root, we have finished */
- if (parent == NULL) {
- DBG("OF: reached root node\n");
- result = of_read_number(addr, na);
- break;
- }
-
- /* Get new parent bus and counts */
- pbus = of_match_bus(parent);
- pbus->count_cells(dev, &pna, &pns);
- if (!OF_CHECK_COUNTS(pna, pns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
- break;
- }
-
- DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
- pbus->name, pna, pns, parent->full_name);
-
- /* Apply bus translation */
- if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
- break;
-
- /* Complete the move up one level */
- na = pna;
- ns = pns;
- bus = pbus;
-
- of_dump_addr("OF: one level translation:", addr, na);
- }
- bail:
- of_node_put(parent);
- of_node_put(dev);
-
- return result;
-}
-
-u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
-{
- return __of_translate_address(dev, in_addr, "ranges");
-}
-EXPORT_SYMBOL(of_translate_address);
-
-u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
-{
- return __of_translate_address(dev, in_addr, "dma-ranges");
-}
-EXPORT_SYMBOL(of_translate_dma_address);
-
-const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
- unsigned int *flags)
-{
- const u32 *prop;
- unsigned int psize;
- struct device_node *parent;
- struct of_bus *bus;
- int onesize, i, na, ns;
-
- /* Get parent & match bus type */
- parent = of_get_parent(dev);
- if (parent == NULL)
- return NULL;
- bus = of_match_bus(parent);
- bus->count_cells(dev, &na, &ns);
- of_node_put(parent);
- if (!OF_CHECK_COUNTS(na, ns))
- return NULL;
-
- /* Get "reg" or "assigned-addresses" property */
- prop = of_get_property(dev, bus->addresses, &psize);
- if (prop == NULL)
- return NULL;
- psize /= 4;
-
- onesize = na + ns;
- for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
- if (i == index) {
- if (size)
- *size = of_read_number(prop + na, ns);
- if (flags)
- *flags = bus->get_flags(prop);
- return prop;
- }
- return NULL;
-}
-EXPORT_SYMBOL(of_get_address);
-
void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
unsigned long *busno, unsigned long *phys, unsigned long *size)
{
diff --git a/drivers/of/address.c b/drivers/of/address.c
index c381955..2a905d5 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -1,11 +1,522 @@
#include <linux/io.h>
#include <linux/ioport.h>
+#include <linux/module.h>
#include <linux/of_address.h>
+#include <linux/pci_regs.h>
+#include <linux/string.h>
-int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
- struct resource *r)
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+static struct of_bus *of_match_bus(struct device_node *np);
+static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r);
+
+/* Debug utility */
+#ifdef DEBUG
+static void of_dump_addr(const char *s, const u32 *addr, int na)
+{
+ printk(KERN_DEBUG "%s", s);
+ while (na--)
+ printk(" %08x", *(addr++));
+ printk("\n");
+}
+#else
+static void of_dump_addr(const char *s, const u32 *addr, int na) { }
+#endif
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ const char *name;
+ const char *addresses;
+ int (*match)(struct device_node *parent);
+ void (*count_cells)(struct device_node *child,
+ int *addrc, int *sizec);
+ u64 (*map)(u32 *addr, const u32 *range,
+ int na, int ns, int pna);
+ int (*translate)(u32 *addr, u64 offset, int na);
+ unsigned int (*get_flags)(const u32 *addr);
+};
+
+/*
+ * Default translator (generic bus)
+ */
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dev);
+ if (sizec)
+ *sizec = of_n_size_cells(dev);
+}
+
+static u64 of_bus_default_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
+
+ pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_default_translate(u32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = a >> 32;
+ addr[na - 1] = a & 0xffffffffu;
+
+ return 0;
+}
+
+static unsigned int of_bus_default_get_flags(const u32 *addr)
+{
+ return IORESOURCE_MEM;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * PCI bus specific translator
+ */
+
+static int of_bus_pci_match(struct device_node *np)
+{
+ /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
+ return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
+}
+
+static void of_bus_pci_count_cells(struct device_node *np,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 3;
+ if (sizec)
+ *sizec = 2;
+}
+
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ switch((w >> 24) & 0x03) {
+ case 0x01:
+ flags |= IORESOURCE_IO;
+ break;
+ case 0x02: /* 32 bits */
+ case 0x03: /* 64 bits */
+ flags |= IORESOURCE_MEM;
+ break;
+ }
+ if (w & 0x40000000)
+ flags |= IORESOURCE_PREFETCH;
+ return flags;
+}
+
+static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+ unsigned int af, rf;
+
+ af = of_bus_pci_get_flags(addr);
+ rf = of_bus_pci_get_flags(range);
+
+ /* Check address type match */
+ if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
+
+ pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
+ unsigned int *flags)
+{
+ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ if (strcmp(bus->name, "pci")) {
+ of_node_put(parent);
+ return NULL;
+ }
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = of_get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
+ if (size)
+ *size = of_read_number(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_pci_address);
+
+int of_pci_address_to_resource(struct device_node *dev, int bar,
+ struct resource *r)
+{
+ const u32 *addrp;
+ u64 size;
+ unsigned int flags;
+
+ addrp = of_get_pci_address(dev, bar, &size, &flags);
+ if (addrp == NULL)
+ return -EINVAL;
+ return __of_address_to_resource(dev, addrp, size, flags, r);
+}
+EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+#endif /* CONFIG_PCI */
+
+/*
+ * ISA bus specific translator
+ */
+
+static int of_bus_isa_match(struct device_node *np)
+{
+ return !strcmp(np->name, "isa");
+}
+
+static void of_bus_isa_count_cells(struct device_node *child,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = 2;
+ if (sizec)
+ *sizec = 1;
+}
+
+static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ /* Check address type match */
+ if ((addr[0] ^ range[0]) & 0x00000001)
+ return OF_BAD_ADDR;
+
+ /* Read address values, skipping high cell */
+ cp = of_read_number(range + 1, na - 1);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr + 1, na - 1);
+
+ pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n",
+ (unsigned long long)cp, (unsigned long long)s,
+ (unsigned long long)da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
+{
+ return of_bus_default_translate(addr + 1, offset, na - 1);
+}
+
+static unsigned int of_bus_isa_get_flags(const u32 *addr)
+{
+ unsigned int flags = 0;
+ u32 w = addr[0];
+
+ if (w & 1)
+ flags |= IORESOURCE_IO;
+ else
+ flags |= IORESOURCE_MEM;
+ return flags;
+}
+
+/*
+ * Array of bus specific translators
+ */
+
+static struct of_bus of_busses[] = {
+#ifdef CONFIG_PCI
+ /* PCI */
+ {
+ .name = "pci",
+ .addresses = "assigned-addresses",
+ .match = of_bus_pci_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_pci_map,
+ .translate = of_bus_pci_translate,
+ .get_flags = of_bus_pci_get_flags,
+ },
+#endif /* CONFIG_PCI */
+ /* ISA */
+ {
+ .name = "isa",
+ .addresses = "reg",
+ .match = of_bus_isa_match,
+ .count_cells = of_bus_isa_count_cells,
+ .map = of_bus_isa_map,
+ .translate = of_bus_isa_translate,
+ .get_flags = of_bus_isa_get_flags,
+ },
+ /* Default */
+ {
+ .name = "default",
+ .addresses = "reg",
+ .match = NULL,
+ .count_cells = of_bus_default_count_cells,
+ .map = of_bus_default_map,
+ .translate = of_bus_default_translate,
+ .get_flags = of_bus_default_get_flags,
+ },
+};
+
+static struct of_bus *of_match_bus(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(of_busses); i++)
+ if (!of_busses[i].match || of_busses[i].match(np))
+ return &of_busses[i];
+ BUG();
+ return NULL;
+}
+
+static int of_translate_one(struct device_node *parent, struct of_bus *bus,
+ struct of_bus *pbus, u32 *addr,
+ int na, int ns, int pna, const char *rprop)
+{
+ const u32 *ranges;
+ unsigned int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ /* Normally, an absence of a "ranges" property means we are
+ * crossing a non-translatable boundary, and thus the addresses
+ * below the current not cannot be converted to CPU physical ones.
+ * Unfortunately, while this is very clear in the spec, it's not
+ * what Apple understood, and they do have things like /uni-n or
+ * /ht nodes with no "ranges" property and a lot of perfectly
+ * useable mapped devices below them. Thus we treat the absence of
+ * "ranges" as equivalent to an empty "ranges" property which means
+ * a 1:1 translation at that level. It's up to the caller not to try
+ * to translate addresses that aren't supposed to be translated in
+ * the first place. --BenH.
+ */
+ ranges = of_get_property(parent, rprop, &rlen);
+ if (ranges == NULL || rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ pr_debug("OF: no ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ pr_debug("OF: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ pr_debug("OF: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("OF: parent translation for:", addr, pna);
+ pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
+ const char *rprop)
+{
+ struct device_node *parent = NULL;
+ struct of_bus *bus, *pbus;
+ u32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ pr_debug("OF: ** translation for device %s **\n", dev->full_name);
+
+ /* Increase refcount at current level */
+ of_node_get(dev);
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ goto bail;
+ bus = of_match_bus(parent);
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(dev, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ goto bail;
+ }
+ memcpy(addr, in_addr, na * 4);
+
+ pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
+ bus->name, na, ns, parent->full_name);
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ of_node_put(dev);
+ dev = parent;
+ parent = of_get_parent(dev);
+
+ /* If root, we have finished */
+ if (parent == NULL) {
+ pr_debug("OF: reached root node\n");
+ result = of_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = of_match_bus(parent);
+ pbus->count_cells(dev, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
+ dev->full_name);
+ break;
+ }
+
+ pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
+ pbus->name, pna, pns, parent->full_name);
+
+ /* Apply bus translation */
+ if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("OF: one level translation:", addr, na);
+ }
+ bail:
+ of_node_put(parent);
+ of_node_put(dev);
+
+ return result;
+}
+
+u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "ranges");
+}
+EXPORT_SYMBOL(of_translate_address);
+
+u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
+{
+ return __of_translate_address(dev, in_addr, "dma-ranges");
+}
+EXPORT_SYMBOL(of_translate_dma_address);
+
+const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
+ unsigned int *flags)
+{
+ const u32 *prop;
+ unsigned int psize;
+ struct device_node *parent;
+ struct of_bus *bus;
+ int onesize, i, na, ns;
+
+ /* Get parent & match bus type */
+ parent = of_get_parent(dev);
+ if (parent == NULL)
+ return NULL;
+ bus = of_match_bus(parent);
+ bus->count_cells(dev, &na, &ns);
+ of_node_put(parent);
+ if (!OF_CHECK_COUNTS(na, ns))
+ return NULL;
+
+ /* Get "reg" or "assigned-addresses" property */
+ prop = of_get_property(dev, bus->addresses, &psize);
+ if (prop == NULL)
+ return NULL;
+ psize /= 4;
+
+ onesize = na + ns;
+ for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
+ if (i == index) {
+ if (size)
+ *size = of_read_number(prop + na, ns);
+ if (flags)
+ *flags = bus->get_flags(prop);
+ return prop;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_get_address);
+
+static int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
+ u64 size, unsigned int flags,
+ struct resource *r)
{
u64 taddr;
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 474b794..cc567df 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -3,9 +3,7 @@
#include <linux/ioport.h>
#include <linux/of.h>
-extern int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
- u64 size, unsigned int flags,
- struct resource *r);
+extern u64 of_translate_address(struct device_node *np, const u32 *addr);
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
extern void __iomem *of_iomap(struct device_node *device, int index);
^ permalink raw reply related
* [PATCH 6/6] of/device: populate platform_device (of_device) resource table on allocation
From: Grant Likely @ 2010-06-08 14:26 UTC (permalink / raw)
To: ben, sfr, monstr, microblaze-uclinux, devicetree-discuss,
jeremy.kerr, linuxppc-dev
In-Reply-To: <20100608142152.26088.1108.stgit@angua>
When allocating a platform_device to represent an OF node, also allocate
space for the resource table and populate it with IRQ and reg property
information. This change is in preparation for merging the
of_platform_bus_type with the platform_bus_type so that existing
platform_driver code can retrieve base addresses and IRQs data.
Background: a previous commit removed struct of_device and made it a
#define alias for platform_device.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: Michal Simek <monstr@monstr.eu>
CC: Grant Likely <grant.likely@secretlab.ca>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Stephen Rothwell <sfr@canb.auug.org.au>
CC: microblaze-uclinux@itee.uq.edu.au
CC: linuxppc-dev@ozlabs.org
CC: devicetree-discuss@lists.ozlabs.org
---
drivers/of/platform.c | 31 ++++++++++++++++++++++++++++---
1 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 4bb898d..10ad0b6 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -441,16 +441,41 @@ struct of_device *of_device_alloc(struct device_node *np,
struct device *parent)
{
struct of_device *dev;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ int rc, i, num_reg = 0, num_irq = 0;
+ struct resource *res, temp_res;
+
+ /* First count how many resources are needed */
+ while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+ num_reg++;
+ while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ)
+ num_irq++;
+
+ /* Allocate the device including space for the resource table, and
+ * initialize it. */
+ i = num_reg + num_irq;
+ dev = kzalloc(sizeof(*dev) + (sizeof(struct resource) * i), GFP_KERNEL);
if (!dev)
return NULL;
-
dev->dev.of_node = of_node_get(np);
dev->dev.dma_mask = &dev->archdata.dma_mask;
dev->dev.parent = parent;
dev->dev.release = of_release_dev;
+ /* Populate the resource table */
+ if (num_irq || num_reg) {
+ dev->resource = (void*)&dev[1];
+ dev->num_resources = num_reg + num_irq;
+ res = dev->resource;
+ for (i = 0; i < num_reg; i++, res++) {
+ rc = of_address_to_resource(np, i, res);
+ WARN_ON(rc);
+ }
+ for (i = 0; i < num_irq; i++, res++) {
+ rc = of_irq_to_resource(np, i, res);
+ WARN_ON(rc == NO_IRQ);
+ }
+ }
+
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
else
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox