* Re: [PATCH 6/8] powerpc 8xx: cascade eoi will be performed by generic_handle_irq handler
From: Benjamin Herrenschmidt @ 2011-05-26 3:32 UTC (permalink / raw)
To: Milton Miller; +Cc: linuxppc-dev
In-Reply-To: <8xx-cascade-eoi@mdm.bga.com>
On Wed, 2011-05-25 at 01:34 -0500, Milton Miller wrote:
> The 8xx cpm_cascade was calling irq_eoi for the cascaded irq,
> but that will already have been called by the handle_fasteoi_irq
> that generic_handle_irq will call. The handler is set in
> arch/powerpc/sysdev/cpm1.c by the host map routine.
No it won't unless I'm missing something. The flow handler
(handle_fasteoi_irq) is going to be replaced by the chained handler when
mpc8xx_pics_init() calls irq_set_chained_handle(irq, cpm_cascade) no ?
Cheers,
Ben.
> Signed-off-by: Milton Miller <miltonm@bga.com>
>
> Index: work.git/arch/powerpc/platforms/8xx/m8xx_setup.c
> ===================================================================
> --- work.git.orig/arch/powerpc/platforms/8xx/m8xx_setup.c 2011-05-18 22:50:38.983498572 -0500
> +++ work.git/arch/powerpc/platforms/8xx/m8xx_setup.c 2011-05-18 22:52:48.920532258 -0500
> @@ -221,15 +221,9 @@ static void cpm_cascade(unsigned int irq
> struct irq_chip *chip;
> int cascade_irq;
>
> - if ((cascade_irq = cpm_get_irq()) >= 0) {
> - struct irq_desc *cdesc = irq_to_desc(cascade_irq);
> -
> + if ((cascade_irq = cpm_get_irq()) >= 0)
> generic_handle_irq(cascade_irq);
>
> - chip = irq_desc_get_chip(cdesc);
> - chip->irq_eoi(&cdesc->irq_data);
> - }
> -
> chip = irq_desc_get_chip(desc);
> chip->irq_eoi(&desc->irq_data);
> }
^ permalink raw reply
* [PATCH v7] powerpc: Force page alignment for initrd reserved memory
From: Dave Carroll @ 2011-05-26 2:32 UTC (permalink / raw)
To: Milton Miller; +Cc: Dave Carroll, LPPC, LKML
In-Reply-To: <initrd-align-v5-reply@mdm.bga.com>
From: Dave Carroll <dcarroll@astekcorp.com>
When using 64K pages with a separate cpio rootfs, U-Boot will align
the rootfs on a 4K page boundary. When the memory is reserved, and
subsequent early memblock_alloc is called, it will allocate memory
between the 64K page alignment and reserved memory. When the reserved
memory is subsequently freed, it is done so by pages, causing the
early memblock_alloc requests to be re-used, which in my case, caused
the device-tree to be clobbered.
This patch forces the reserved memory for initrd to be kernel page
aligned, and will move the device tree if it overlaps with the range
extension of initrd. This patch will also consolidate the identical
function free_initrd_mem() from mm/init_32.c, init_64.c to mm/mem.c,
and adds the same range extension when freeing initrd.
Many thanks to Milton Miller for his input on this patch.
Signed-off-by: Dave Carroll <dcarroll@astekcorp.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
* The previous patch [v6] was the wrong copy, sorry ...
arch/powerpc/kernel/prom.c | 21 ++++++++++++++++++---
arch/powerpc/mm/init_32.c | 15 ---------------
arch/powerpc/mm/init_64.c | 13 -------------
arch/powerpc/mm/mem.c | 19 +++++++++++++++++++
4 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 48aeb55..86966a0 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -81,12 +81,24 @@ static int __init early_parse_mem(char *p)
return 0;
}
early_param("mem", early_parse_mem);
+/**
+ * overlaps_initrd - check for overlap with page aligned extension of
+ * initrd.
+ */
+static inline int overlaps_initrd(unsigned long start, unsigned long size)
+{
+ if (!initrd_start)
+ return 0;
+ return (start + size) > _ALIGN_DOWN(initrd_start, PAGE_SIZE) &&
+ start <= _ALIGN_UP(initrd_end, PAGE_SIZE);
+}
/**
* move_device_tree - move tree to an unused area, if needed.
*
* The device tree may be allocated beyond our memory limit, or inside the
- * crash kernel region for kdump. If so, move it out of the way.
+ * crash kernel region for kdump, or within the page aligned range of initrd.
+ * If so, move it out of the way.
*/
static void __init move_device_tree(void)
{
@@ -99,7 +111,8 @@ static void __init move_device_tree(void)
size = be32_to_cpu(initial_boot_params->totalsize);
if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
- overlaps_crashkernel(start, size)) {
+ overlaps_crashkernel(start, size) ||
+ overlaps_initrd(start, size)) {
p = __va(memblock_alloc(size, PAGE_SIZE));
memcpy(p, initial_boot_params, size);
initial_boot_params = (struct boot_param_header *)p;
@@ -555,7 +568,9 @@ static void __init early_reserve_mem(void)
#ifdef CONFIG_BLK_DEV_INITRD
/* then reserve the initrd, if any */
if (initrd_start && (initrd_end > initrd_start))
- memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
+ memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE),
+ _ALIGN_UP(initrd_end, PAGE_SIZE) -
+ _ALIGN_DOWN(initrd_start, PAGE_SIZE));
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index d65b591..5de0f25 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -223,21 +223,6 @@ void free_initmem(void)
#undef FREESEC
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
- if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
-}
-#endif
-
-
#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
void setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size)
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 6374b21..7591a97 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -99,19 +99,6 @@ void free_initmem(void)
((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
- if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
-}
-#endif
static void pgd_ctor(void *addr)
{
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 57e545b..f60e44e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -160,6 +160,25 @@ walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
}
EXPORT_SYMBOL_GPL(walk_system_ram_range);
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start >= end)
+ return;
+
+ start = _ALIGN_DOWN(start, PAGE_SIZE);
+ end = _ALIGN_UP(end, PAGE_SIZE);
+ printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+ (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ }
+}
+#endif
+
/*
* Initialize the bootmem system and give it all the memory we
* have available. If we are using highmem, we only put the
--
1.7.4
^ permalink raw reply related
* [PATCH v6] powerpc: Force page alignment for initrd reserved memory
From: Dave Carroll @ 2011-05-26 2:00 UTC (permalink / raw)
To: Milton Miller; +Cc: Dave Carroll, LPPC, LKML
In-Reply-To: <initrd-align-v5-reply@mdm.bga.com>
From: Dave Carroll <dcarroll@astekcorp.com>
When using 64K pages with a separate cpio rootfs, U-Boot will align
the rootfs on a 4K page boundary. When the memory is reserved, and
subsequent early memblock_alloc is called, it will allocate memory
between the 64K page alignment and reserved memory. When the reserved
memory is subsequently freed, it is done so by pages, causing the
early memblock_alloc requests to be re-used, which in my case, caused
the device-tree to be clobbered.
This patch forces the reserved memory for initrd to be kernel page
aligned, and will move the device tree if it overlaps with the range
extension of initrd. This patch will also consolidate the identical
function free_initrd_mem() from mm/init_32.c, init_64.c to mm/mem.c,
and adds the same range extension when freeing initrd.
Many thanks to Milton Miller for his input on this patch.
Signed-off-by: Dave Carroll <dcarroll@astekcorp.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/prom.c | 21 ++++++++++++++++++---
arch/powerpc/mm/init_32.c | 15 ---------------
arch/powerpc/mm/init_64.c | 13 -------------
arch/powerpc/mm/mem.c | 19 +++++++++++++++++++
4 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 48aeb55..86966a0 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -81,12 +81,24 @@ static int __init early_parse_mem(char *p)
return 0;
}
early_param("mem", early_parse_mem);
+/**
+ * overlaps_initrd - check for overlap with page aligned extension of
+ * initrd.
+ */
+static inline int overlaps_initrd(unsigned long start, unsigned long end)
+{
+ if (!initrd_start)
+ return 0;
+ return (start + size) > _ALIGN_DOWN(initrd_start, PAGE_SIZE) &&
+ start <= _ALIGN_UP(initrd_end, PAGE_SIZE);
+}
/**
* move_device_tree - move tree to an unused area, if needed.
*
* The device tree may be allocated beyond our memory limit, or inside the
- * crash kernel region for kdump. If so, move it out of the way.
+ * crash kernel region for kdump, or within the page aligned range of initrd.
+ * If so, move it out of the way.
*/
static void __init move_device_tree(void)
{
@@ -99,7 +111,8 @@ static void __init move_device_tree(void)
size = be32_to_cpu(initial_boot_params->totalsize);
if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
- overlaps_crashkernel(start, size)) {
+ overlaps_crashkernel(start, size) ||
+ overlaps_initrd(start, size) {
p = __va(memblock_alloc(size, PAGE_SIZE));
memcpy(p, initial_boot_params, size);
initial_boot_params = (struct boot_param_header *)p;
@@ -555,7 +568,9 @@ static void __init early_reserve_mem(void)
#ifdef CONFIG_BLK_DEV_INITRD
/* then reserve the initrd, if any */
if (initrd_start && (initrd_end > initrd_start))
- memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
+ memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE),
+ _ALIGN_UP(initrd_end, PAGE_SIZE) -
+ _ALIGN_DOWN(initrd_start, PAGE_SIZE));
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index d65b591..5de0f25 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -223,21 +223,6 @@ void free_initmem(void)
#undef FREESEC
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
- if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
-}
-#endif
-
-
#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
void setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size)
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 6374b21..7591a97 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -99,19 +99,6 @@ void free_initmem(void)
((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
- if (start < end)
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
-}
-#endif
static void pgd_ctor(void *addr)
{
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 57e545b..f60e44e 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -160,6 +160,25 @@ walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
}
EXPORT_SYMBOL_GPL(walk_system_ram_range);
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start >= end)
+ return;
+
+ start = _ALIGN_DOWN(start, PAGE_SIZE);
+ end = _ALIGN_UP(end, PAGE_SIZE);
+ printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+ (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ }
+}
+#endif
+
/*
* Initialize the bootmem system and give it all the memory we
* have available. If we are using highmem, we only put the
--
1.7.4
^ permalink raw reply related
* Re: [rtc-linux] [PATCH] RTC driver(Linux) for PT7C4338 chip.
From: Andrew Morton @ 2011-05-25 23:56 UTC (permalink / raw)
To: Jain Priyanka-B32167
Cc: a.zummo@towertech.it, linuxppc-dev@lists.ozlabs.org,
rtc-linux@googlegroups.com, p_gortmaker@yahoo.com
In-Reply-To: <470DB7CE2CD0944E9436E7ADEFC02FE313B36C@039-SN1MPN1-003.039d.mgd.msft.net>
On Thu, 10 Mar 2011 11:06:27 +0000
Jain Priyanka-B32167 <B32167@freescale.com> wrote:
> Hi Wolfram,
>
>
> > -----Original Message-----
> > From: Wolfram Sang [mailto:w.sang@pengutronix.de]
> > Sent: Thursday, March 10, 2011 2:24 PM
> > To: Jain Priyanka-B32167
> > Cc: rtc-linux@googlegroups.com; linuxppc-dev@lists.ozlabs.org;
> > a.zummo@towertech.it; p_gortmaker@yahoo.com; akpm@linux-foundation.org
> > Subject: Re: [rtc-linux] [PATCH] RTC driver(Linux) for PT7C4338 chip.
> >
> > Hi Priyanka,
> >
> > > Though register-set looks identical but features were different.
> >
> > Can you tell what exactly is different?
> I will check both the devices data sheets again in detail and will get back on this.
> >
> > > And also manufacturer is different.
> >
> > That does not matter. If you look at ds_type, there are already different
> > manufacturers. They will be correctly distinguished by i2c_device_id. The
> > name of the driver itself is, well, just a name.
> >
> > > But still it might be possible that we can reuse ds1307.c with some
> > > modification.
> >
> > I agree. The driver already supports some variants. Adding one more
> > should not hurt. See 97f902b7be4dd6ba03c6aa8d3400783ed687ebd1 for an
> > example which added ds3231 support.
> >
> > > But if I look at the drivers present in drivers/rtc folder. Most of
> > > them looks similar but still there are different drivers for different
> > > chips.
> >
> > Yes, it probably could be cleaned up if somebody had the time/hardware.
> >
> > > Please suggest which way is more preferred: modifying existing
> > > drivers(of different manufacturer) or writing new driver.
> >
> > Ususally avoiding code duplication is good, it reduces maintenance
> > burden. However, if adding the support turns out to make the original
> > code unreadable or hard to follow, a new driver might be justified. This
> > is why it is important to understand the differences of the chip as a
> > first step. (I have the feeling, that modifying is the way to go here,
> > though).
> >
>
> I will explore possibility of using ds1307 driver for this.
>
Has there been any movement here?
^ permalink raw reply
* Re: [PATCH 7/8] powerpc irq: protect irq_radix_revmap_lookup against irq_free_virt
From: Paul E. McKenney @ 2011-05-25 21:31 UTC (permalink / raw)
To: Milton Miller; +Cc: linuxppc-dev
In-Reply-To: <rcu-lock-radix-lookup-ppc@mdm.bga.com>
On Wed, May 25, 2011 at 01:34:18AM -0500, Milton Miller wrote:
> The radix-tree code uses call_rcu when freeing internal elements.
> We must protect against the elements being freed while we traverse
> the tree, even if the returned pointer will still be valid.
>
> While preparing a patch to expand the context in which
> irq_radix_revmap_lookup will be called, I realized that the
> radix tree was not locked.
>
> When asked
>
> For a normal call_rcu usage, is it allowed to read the structure in
> irq_enter / irq_exit, without additional rcu_read_lock? Could an
> element freed with call_rcu advance with the cpu still between
> irq_enter/irq_exit (and irq_disabled())?
>
> Paul McKenney replied:
>
> Absolutely illegal to do so. OK for call_rcu_sched(), but a
> flaming bug for call_rcu().
>
> And thank you very much for finding this!!!
>
> Further analysis:
>
> In the current CONFIG_TREE_RCU implementation. CONFIG_TREE_PREEMPT_RCU
> (and CONFIG_TINY_PREEMPT_RCU) uses explicit counters.
>
> These counters are reflected from per-CPU to global in the
> scheduling-clock-interrupt handler, so disabling irq does prevent the
> grace period from completing. But there are real-time implementations
> (such as the one use by the Concurrent guys) where disabling irq
> does -not- prevent the grace period from completing.
>
>
> While an alternative fix would be to switch radix-tree to rcu_sched, I
> don't want to audit the other users of radix trees (nor put alternative
> freeing in the library). The normal overhead for rcu_read_lock and
> unlock are a local counter increment and decrement.
>
> This does not show up in the rcu lockdep because in 2.6.34 commit
> 2676a58c98 (radix-tree: Disable RCU lockdep checking in radix tree)
> deemed it too hard to pass the condition of the protecting lock
> to the library.
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Signed-off-by: Milton Miller <miltonm@bga.com>
>
> Index: work.git/arch/powerpc/kernel/irq.c
> ===================================================================
> --- work.git.orig/arch/powerpc/kernel/irq.c 2011-05-24 21:14:30.860096118 -0500
> +++ work.git/arch/powerpc/kernel/irq.c 2011-05-24 21:15:55.350096024 -0500
> @@ -893,10 +893,13 @@ unsigned int irq_radix_revmap_lookup(str
> return irq_find_mapping(host, hwirq);
>
> /*
> - * No rcu_read_lock(ing) needed, the ptr returned can't go under us
> - * as it's referencing an entry in the static irq_map table.
> + * The ptr returned references the static global irq_map.
> + * but freeing an irq can delete nodes along the path to
> + * do the lookup via call_rcu.
> */
> + rcu_read_lock();
> ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
> + rcu_read_unlock();
>
> /*
> * If found in radix tree, then fine.
^ permalink raw reply
* Re: Booting p4080ds on non-0 cpu
From: McClintock Matthew-B29882 @ 2011-05-25 18:52 UTC (permalink / raw)
To: Gabbasov, Andrew; +Cc: linuxppc-dev@lists.ozlabs.org, Blanchard, Hollis
In-Reply-To: <DBDC8B5977CFF7429A9DBC6C51C7ADE701E81C39@EU1-MAIL.mgc.mentorg.com>
On Wed, May 25, 2011 at 7:16 AM, Gabbasov, Andrew
<Andrew_Gabbasov@mentor.com> wrote:
> Hello Matthew,
>
> You have made a patch
> "powerpc/fsl_booke:=A0Add=A0support=A0to=A0boot=A0from=A0core=A0other=A0t=
han=A00" some time
> ago, so you probably worked with booting the kernel on a cpu subset,
> particularly on the core other than 0.
>
> Could you please describe any details how you ran the kernel from u-boot =
on
> a non-0 cpu?
I did this via kexec not via u-boot. In this method I would reboot on
any one of the cores and it would bring up the other cores.
> I have a problem trying to boot linux on p4080ds platform on any non-0 cp=
u
> (as a first step to running AMP or mixed AMP/SMP configuration). I'm tryi=
ng
> to run 2.6.34.6 kernel with some Freescale patches in SMP configuration w=
ith
> full original device tree and device tree with some cpu nodes removed. I'=
m
> using the u-boot script, shown at the bottom of this message.
>
> If I run "bootm go" after the script commands (thus running the kernel on
> cpu 0), the kernel runs fine.
>
> When I'm trying to run the SMP kernel with full device tree on cpu 1 usin=
g
> the following commands after the script:
> =A0 fdt boot 1
> =A0 cpu 1 release 0 1 c00000 -
> the kernel begins to run, but soon crashes. Possible reasons
> are:=A0"Unrecoverable FP Unavailable Exception", at nearly random
> place;=A0memory allocation errors somewhere in DPAA=A0code and then segme=
ntation
> fault (sig 11); unknown exception (sig 4).=A0Sometimes it doesn't even sh=
ow
> anything on the console (too early exception?), but sometimes it boots
> successfully up to the shell prompt.
Is the single core boot stable at this point?
> When I'm trying to run the SMP kernel with the device tree with cpu 0
> stripped out (commented out the whole cpu0 node and all properties referr=
ing
> to it with &cpu0), using the following commands after the script:
> =A0 fdt boot 1
> =A0 cpu 1 release 0 0 c00000 -
> =A0 [Note the difference in the parameter to 'cpu 1 release' command,
> =A0=A0=A0 it should be a logical cpu number, which is different]
> the result is almost the same, the kernel crashes too. The reasons are
> similar to the above, with more often "Unrecoverable FP Unavailable
> Exception".
Can you send me the kernel boot logs and kernel defconfig? (off list perhap=
s)
>
> Can you give any advise why can this happen, and what I could be doing
> wrong?
Did you build your kernel relocatable? Did you use the -b option when
compiling your device tree? We do have a hypervisor for this part
which might be a more suitable and tested solution depending on what
you are trying to accomplish. I'm not sure that anyone has explicitly
tested AMP on a p4080.
-M=
^ permalink raw reply
* Re: [PATCH 5/8] powerpc: override dma_get_required_mask by platform hook and ops
From: Nishanth Aravamudan @ 2011-05-25 18:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: cbe-oss-dev, FUJITA Tomonori, Arnd Bergmann, Sonny Rao,
devicetree-discuss, linux-kernel, Milton Miller, Paul Mackerras,
Anton Blanchard, Will Schmidt, Andrew Morton, linuxppc-dev
In-Reply-To: <20110519174625.GA3338@us.ibm.com>
Ben,
On 19.05.2011 [10:46:25 -0700], Nishanth Aravamudan wrote:
> On 19.05.2011 [17:43:56 +1000], Benjamin Herrenschmidt wrote:
> > On Wed, 2011-05-11 at 15:25 -0700, Nishanth Aravamudan wrote:
> > > From: Milton Miller <miltonm@bga.com>
> > >
> > > The hook dma_get_required_mask is supposed to return the mask required
> > > by the platform to operate efficently. The generic version of
> > > dma_get_required_mask in driver/base/platform.c returns a mask based
> > > only on max_pfn. However, this is likely too big for iommu systems
> > > and could be too small for platforms that require a dma offset or have
> > > a secondary window at a high offset.
> >
> > The result of those 3 patches doesn't build on top of my current tree,
> > the generic dma_ops lacks the dma_get_required_mask hook. I'll have a
> > look again after the merge window.
>
> Hrm, I think it's because for whatever reason [1] I forgot to cc you on 6/8?
>
> https://lkml.org/lkml/2011/5/11/473
Were you able to find the patch I refer to above?
Thanks,
Nish
--
Nishanth Aravamudan <nacc@us.ibm.com>
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH 3/5] v2 seccomp_filters: Enable ftrace-based system call filtering
From: Thomas Gleixner @ 2011-05-25 17:48 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-mips, linux-sh, Peter Zijlstra, Frederic Weisbecker,
Heiko Carstens, Oleg Nesterov, David Howells, Paul Mackerras,
Eric Paris, H. Peter Anvin, sparclinux, Jiri Slaby, linux-s390,
Russell King, x86, James Morris, Linus Torvalds, Ingo Molnar,
kees.cook, Serge E. Hallyn, Steven Rostedt, Martin Schwidefsky,
linux-arm-kernel, Michal Marek, Michal Simek, Will Drewry,
linuxppc-dev, linux-kernel, Ralf Baechle, Paul Mundt, Tejun Heo,
linux390, Andrew Morton, agl, David S. Miller
In-Reply-To: <20110525150153.GE29179@elte.hu>
On Wed, 25 May 2011, Ingo Molnar wrote:
> * Thomas Gleixner <tglx@linutronix.de> wrote:
> > On Tue, 24 May 2011, Ingo Molnar wrote:
> > > * Peter Zijlstra <peterz@infradead.org> wrote:
> > >
> > > > On Tue, 2011-05-24 at 10:59 -0500, Will Drewry wrote:
> > > > > include/linux/ftrace_event.h | 4 +-
> > > > > include/linux/perf_event.h | 10 +++++---
> > > > > kernel/perf_event.c | 49 +++++++++++++++++++++++++++++++++++++---
> > > > > kernel/seccomp.c | 8 ++++++
> > > > > kernel/trace/trace_syscalls.c | 27 +++++++++++++++++-----
> > > > > 5 files changed, 82 insertions(+), 16 deletions(-)
> > > >
> > > > I strongly oppose to the perf core being mixed with any sekurity voodoo
> > > > (or any other active role for that matter).
> > >
> > > I'd object to invisible side-effects as well, and vehemently so. But note how
> > > intelligently it's used here: it's explicit in the code, it's used explicitly
> > > in kernel/seccomp.c and the event generation place in
> > > kernel/trace/trace_syscalls.c.
> > >
> > > So this is a really flexible solution IMO and does not extend events with some
> > > invisible 'active' role. It extends the *call site* with an open-coded active
> > > role - which active role btw. already pre-existed.
> >
> > We do _NOT_ make any decision based on the trace point so what's the
> > "pre-existing" active role in the syscall entry code?
>
> The seccomp code we are discussing in this thread.
That's proposed code and has absolutely nothing to do with the
existing trace point semantics.
> > I'm all for code reuse and reuse of interfaces, but this is completely
> > wrong. Instrumentation and security decisions are two fundamentally
> > different things and we want them kept separate. Instrumentation is
> > not meant to make decisions. Just because we can does not mean that it
> > is a good idea.
>
> Instrumentation does not 'make decisions': the calling site, which is
> already emitting both the event and wants to do decisions based on
> the data that also generates the event wants to do decisions.
You can repeat that as often as you want, it does not make it more
true. Fact is that the decision is made in the middle of the perf code.
> + /* Transition the task if required. */
> + if (ctx->type == task_context && event->attr.require_secure) {
> +#ifdef CONFIG_SECCOMP
> + /* Don't allow perf events to escape mode = 1. */
> + if (!current->seccomp.mode)
> + current->seccomp.mode = 2;
> +#endif
> + }
and further down
> + if (event->attr.err_on_discard)
> + ok = -EACCES;
> Those decisions *will be made* and you cannot prevent that, the only
> open question is can it reuse code intelligently, which code it is
> btw. already calling for observation reasons?
The tracepoint is called for observation reasons and now you make it a
decision function. That's what I call abuse.
> ( Note that pure observers wont be affected and note that pure
> observation call sites are not affected either. )
Hahaha, they still have to run through the additional code when
seccomp is enabled and we still have to propagate the return value
down to the point where the tracepoint itself is. You call that not
affected?
> > So what the current approach does is:
> >
> > - abuse the existing ftrace syscall hook by adding a return value to
> > the tracepoint.
> >
> > So we need to propagate that for every tracepoint just because we
> > have a single user.
>
> This is a technical criticism i share with you and i think it can be
> fixed - i outlined it to Will yesterday.
>
> And no, if done cleanly it's not 'abuse' to reuse code. Could we wait
> for the first clean iteration of this patch instead of rushing
> judgement prematurely?
There is no way to do it cleanly. It always comes for the price that
you add additional code into the tracing code path. And there are
other people who try hard to remove stuff to recude the overhead which
is caused by instrumentation.
> > - abuse the perf per task mechanism
> >
> > Just because we have per task context in perf does not mean that we
> > pull everything and the world which requires per task context into
> > perf. The security folks have per task context already so security
> > related stuff wants to go there.
>
> We do not pull 'everything and the world' in, but code that wants to
> process events in places that already emit events surely sounds
> related to me :-)
We have enough places where different independent parts of the kernel
want to hook into for obvious reasons.
We have notifiers for those where performance does not matter much and
we have separate calls into the independent functions where it matters
or where we need to evaluate the results in specific ways.
So now you turn instrumentation into a security mechanism, which
"works" nicely for a particular purpose, i.e. decision on a particular
syscall number. Now, how do you make that work when a decision has to
be made on more than a simple match, e.g. syscall number + arguments ?
Not at all, unless you add more complexity and arbitrary callbacks
into the instrumentation code.
> > Brilliant, we have already two ABIs (perf/ftrace) to support and at
> > the same time we urgently need to solve the problem of better
> > integration of those two. So adding a third completely unrelated
> > component with a guaranteed ABI is just making this even more complex.
>
> So your solution is to add yet another ABI for seccomp and to keep
> seccomp a limited hack forever, just because you are not interested
> in security?
Well, I'm interested in security, but I'm neither interested in
security decisions inside instrumentation code nor in security models
which are limited hacks by definition unless you want to add callback
complexities to the instrumentation code.
It all looks nice and charming with this minimalistic use case, but
add real features to it and it gets messy in a split second and you
can't hold that off once you started to allow A. And you clearly
stated that you want to have more trace point based security features
than the simple syscall number filtering.
> I think we want fewer ABIs and more flexible/reusable facilities.
I'm all for that, but security and instrumentation are different
beasts.
> > We can factor out the filtering code and let the security dudes
> > reuse it for their own purposes. That makes them to have their own
> > interfaces and does not impose any restrictions upon the
> > tracing/perf ones. And really security stuff wants to be integrated
> > into the existing security frameworks and not duct taped into
> > perf/trace just because it's a conveniant hack around limitiations
> > of the existing security stuff.
>
> You are missing what i tried to point out in earlier discussions:
> from a security design POV this isnt just about the system call
> boundary. If this seccomp variant is based on events then it could
> grow proper security checks in other places as well, in places where
> we have some sort of object observation event anyway.
Right, that requires callbacks and more stuff to do object based
observation and ties a trace point into a place where it might not
make sense after a while, but the security decision wants to stay at
that place. The syscall example is so tempting because it's simplistic
and easy to solve, but every extension to that model is going to
create a nightmare.
You are duct taping stuff together which has totally different
semantics and requirements. And your only argument is reuse of
existing code. That's a good argument in principle, but there is a
fundamental difference between intelligent reuse and enforcing it just
for reuse sake.
> So this is opens up possibilities to reuse and unify code on a very
> broad basis.
By making a total mess out of it?
> So yes, over-integration is obviously wrong - but so is needless
> fragmentation.
Right. And this falls into the category of over-integration. We have
people working on security and they are working on stacked security
models, so where is the justification to start another security
framework inside the instrumentation code which is completely non
interoperable with the existing ones?
> If anything then that should tell you something that events and
> seccomp are not just casually related ...
They happen to have the hook at the same point in the source and for
pure coincidence it works because the problem to solve is extremly
simplistic. And that's why the diffstat is minimalistic, but that does
not prove anything.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH 3/5] v2 seccomp_filters: Enable ftrace-based system call filtering
From: Peter Zijlstra @ 2011-05-25 17:43 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-mips, linux-sh, Frederic Weisbecker, Heiko Carstens,
Oleg Nesterov, David Howells, Paul Mackerras, Eric Paris,
H. Peter Anvin, sparclinux, Jiri Slaby, linux-s390, Russell King,
x86, James Morris, Linus Torvalds, Ingo Molnar, kees.cook,
Serge E. Hallyn, Steven Rostedt, Martin Schwidefsky,
Thomas Gleixner, linux-arm-kernel, Michal Marek, Michal Simek,
Will Drewry, linuxppc-dev, linux-kernel, Ralf Baechle, Paul Mundt,
Tejun Heo, linux390, Andrew Morton, agl, David S. Miller
In-Reply-To: <20110525150153.GE29179@elte.hu>
On Wed, 2011-05-25 at 17:01 +0200, Ingo Molnar wrote:
> > We do _NOT_ make any decision based on the trace point so what's the
> > "pre-existing" active role in the syscall entry code?
>=20
> The seccomp code we are discussing in this thread.=20
That isn't pre-existing, that's proposed.
But face it, you can argue until you're blue in the face, but both tglx
and I will NAK any and all patches that extend perf/ftrace beyond the
passive observing role.
Your arguments appear to be as non-persuasive to us as ours are to you,
so please drop this endeavor and let the security folks sort it on their
own and let's get back to doing useful work.=20
^ permalink raw reply
* Re: [PATCH 3/5] v2 seccomp_filters: Enable ftrace-based system call filtering
From: Ingo Molnar @ 2011-05-25 15:01 UTC (permalink / raw)
To: Thomas Gleixner
Cc: linux-mips, linux-sh, Peter Zijlstra, Frederic Weisbecker,
Heiko Carstens, Oleg Nesterov, David Howells, Paul Mackerras,
Eric Paris, H. Peter Anvin, sparclinux, Jiri Slaby, linux-s390,
Russell King, x86, James Morris, Linus Torvalds, Ingo Molnar,
kees.cook, Serge E. Hallyn, Steven Rostedt, Martin Schwidefsky,
linux-arm-kernel, Michal Marek, Michal Simek, Will Drewry,
linuxppc-dev, linux-kernel, Ralf Baechle, Paul Mundt, Tejun Heo,
linux390, Andrew Morton, agl, David S. Miller
In-Reply-To: <alpine.LFD.2.02.1105242239230.3078@ionos>
* Thomas Gleixner <tglx@linutronix.de> wrote:
> On Tue, 24 May 2011, Ingo Molnar wrote:
> > * Peter Zijlstra <peterz@infradead.org> wrote:
> >
> > > On Tue, 2011-05-24 at 10:59 -0500, Will Drewry wrote:
> > > > include/linux/ftrace_event.h | 4 +-
> > > > include/linux/perf_event.h | 10 +++++---
> > > > kernel/perf_event.c | 49 +++++++++++++++++++++++++++++++++++++---
> > > > kernel/seccomp.c | 8 ++++++
> > > > kernel/trace/trace_syscalls.c | 27 +++++++++++++++++-----
> > > > 5 files changed, 82 insertions(+), 16 deletions(-)
> > >
> > > I strongly oppose to the perf core being mixed with any sekurity voodoo
> > > (or any other active role for that matter).
> >
> > I'd object to invisible side-effects as well, and vehemently so. But note how
> > intelligently it's used here: it's explicit in the code, it's used explicitly
> > in kernel/seccomp.c and the event generation place in
> > kernel/trace/trace_syscalls.c.
> >
> > So this is a really flexible solution IMO and does not extend events with some
> > invisible 'active' role. It extends the *call site* with an open-coded active
> > role - which active role btw. already pre-existed.
>
> We do _NOT_ make any decision based on the trace point so what's the
> "pre-existing" active role in the syscall entry code?
The seccomp code we are discussing in this thread.
> I'm all for code reuse and reuse of interfaces, but this is completely
> wrong. Instrumentation and security decisions are two fundamentally
> different things and we want them kept separate. Instrumentation is
> not meant to make decisions. Just because we can does not mean that it
> is a good idea.
Instrumentation does not 'make decisions': the calling site, which is
already emitting both the event and wants to do decisions based on
the data that also generates the event wants to do decisions.
Those decisions *will be made* and you cannot prevent that, the only
open question is can it reuse code intelligently, which code it is
btw. already calling for observation reasons?
( Note that pure observers wont be affected and note that pure
observation call sites are not affected either. )
> So what the current approach does is:
>
> - abuse the existing ftrace syscall hook by adding a return value to
> the tracepoint.
>
> So we need to propagate that for every tracepoint just because we
> have a single user.
This is a technical criticism i share with you and i think it can be
fixed - i outlined it to Will yesterday.
And no, if done cleanly it's not 'abuse' to reuse code. Could we wait
for the first clean iteration of this patch instead of rushing
judgement prematurely?
> - abuse the perf per task mechanism
>
> Just because we have per task context in perf does not mean that we
> pull everything and the world which requires per task context into
> perf. The security folks have per task context already so security
> related stuff wants to go there.
We do not pull 'everything and the world' in, but code that wants to
process events in places that already emit events surely sounds
related to me :-)
> - abuse the perf/ftrace interfaces
>
> One of the arguments was that perf and ftrace have permission which
> are not available from the existing security interfaces. That's not
> at all a good reason to abuse these interfaces. Let the security
> folks sort out the problem on their end and do not impose any
> expectations on perf/ftrace which we have to carry around forever.
>
> Yes, it can be made working with a relatively small patch, but it has
> a very nasty side effect:
>
> You add another user space visible ABI to the existing perf/ftrace
> mess which needs to be supported forever.
What mess? I'm not aware of a mess - other than the ftrace API which
is not used by this patch.
> Brilliant, we have already two ABIs (perf/ftrace) to support and at
> the same time we urgently need to solve the problem of better
> integration of those two. So adding a third completely unrelated
> component with a guaranteed ABI is just making this even more complex.
So your solution is to add yet another ABI for seccomp and to keep
seccomp a limited hack forever, just because you are not interested
in security?
I think we want fewer ABIs and more flexible/reusable facilities.
> We can factor out the filtering code and let the security dudes
> reuse it for their own purposes. That makes them to have their own
> interfaces and does not impose any restrictions upon the
> tracing/perf ones. And really security stuff wants to be integrated
> into the existing security frameworks and not duct taped into
> perf/trace just because it's a conveniant hack around limitiations
> of the existing security stuff.
You are missing what i tried to point out in earlier discussions:
from a security design POV this isnt just about the system call
boundary. If this seccomp variant is based on events then it could
grow proper security checks in other places as well, in places where
we have some sort of object observation event anyway.
So this is opens up possibilities to reuse and unify code on a very
broad basis.
> You really should stop to see everything as a nail just because the
> only tool you have handy is the perf hammer. perf is about
> instrumentation and we don't want to violate the oldest principle
> of unix to have simple tools which do one thing and do it good.
That is one of the most misunderstood principles of Unix.
The original Unix tool landscape was highly *integrated* and
*unified*, into a very tight codebase that was maintained together.
Yes, there were different, atomic, simple commands but it was all
done together and it was a coherent whole and pleasant to use!
People misunderstood this as a license to fragment the heck out
functionality and build 'simple and stupid' tools that fit nowhere
really and use different, incompatible principles not synced with
each other. That is wrong and harmful.
So yes, over-integration is obviously wrong - but so is needless
fragmentation.
Anyway, i still reserve judgement on this seccomp bit but the patches
so far looked very promising with a very surprisingly small diffstat.
If anything then that should tell you something that events and
seccomp are not just casually related ...
> Even swiss army knifes have the restriction that you can use only
> one tool at a time unless you want to stick the corkscrew through
> your palm when you try to cut bread.
I'm not sure what you are arguing here - do you pine for the DOS days
where you could only use one command at a time?
Thanks,
Ingo
^ permalink raw reply
* Booting p4080ds on non-0 cpu
From: Gabbasov, Andrew @ 2011-05-25 12:16 UTC (permalink / raw)
To: Matthew Mcclintock - Freescale; +Cc: linuxppc-dev, Blanchard, Hollis
In-Reply-To: <DBDC8B5977CFF7429A9DBC6C51C7ADE701E81C32@EU1-MAIL.mgc.mentorg.com>
[-- Attachment #1: Type: text/plain, Size: 2760 bytes --]
Hello Matthew,
You have made a patch "powerpc/fsl_booke: Add support to boot from core other than 0" some time ago, so you probably worked with booting the kernel on a cpu subset, particularly on the core other than 0.
Could you please describe any details how you ran the kernel from u-boot on a non-0 cpu?
I have a problem trying to boot linux on p4080ds platform on any non-0 cpu (as a first step to running AMP or mixed AMP/SMP configuration). I'm trying to run 2.6.34.6 kernel with some Freescale patches in SMP configuration with full original device tree and device tree with some cpu nodes removed. I'm using the u-boot script, shown at the bottom of this message.
If I run "bootm go" after the script commands (thus running the kernel on cpu 0), the kernel runs fine.
When I'm trying to run the SMP kernel with full device tree on cpu 1 using the following commands after the script:
fdt boot 1
cpu 1 release 0 1 c00000 -
the kernel begins to run, but soon crashes. Possible reasons are: "Unrecoverable FP Unavailable Exception", at nearly random place; memory allocation errors somewhere in DPAA code and then segmentation fault (sig 11); unknown exception (sig 4). Sometimes it doesn't even show anything on the console (too early exception?), but sometimes it boots successfully up to the shell prompt.
When I'm trying to run the SMP kernel with the device tree with cpu 0 stripped out (commented out the whole cpu0 node and all properties referring to it with &cpu0), using the following commands after the script:
fdt boot 1
cpu 1 release 0 0 c00000 -
[Note the difference in the parameter to 'cpu 1 release' command,
it should be a logical cpu number, which is different]
the result is almost the same, the kernel crashes too. The reasons are similar to the above, with more often "Unrecoverable FP Unavailable Exception".
Can you give any advise why can this happen, and what I could be doing wrong?
Thanks in advance,
Best regards,
Andrew
setenv kernel_base 00000000
setenv kernel_size 30000000
# Helper variables
setenv kernel_load_offset 01000000
setenv dtb_load_offset 00c00000
setexpr kernel_load_addr $kernel_base + $kernel_load_offset
setexpr dtb_load_addr $kernel_base + $dtb_load_offset
tftp $kernel_load_addr $tftpdir/uImage-p4080ds.bin
tftp $dtb_load_addr $tftpdir/uImage-p4080ds.dtb
setenv bootargs root=/dev/nfs rw nfsroot=$serverip:/tftpboot/$tftpdir/rootfs-4080ds ip=dhcp console=ttyS0,115200 debug
setenv bootm_low $kernel_base
setenv bootm_size $kernel_size
interrupts off
bootm start $kernel_load_addr - $dtb_load_addr
bootm loados
bootm fdt
fdt boardsetup
fdt chosen
bootm prep
# cpu 1 release $kernel_base - $dtb_load_addr -
[-- Attachment #2: Type: text/html, Size: 4813 bytes --]
^ permalink raw reply
* Re: Best Linux choice for POWER7?
From: Michael Neuling @ 2011-05-25 12:23 UTC (permalink / raw)
To: Josh Boyer; +Cc: Gabriel Menini, linuxppc-dev
In-Reply-To: <20110525104311.GB22207@zod.rchland.ibm.com>
> >> I am looking for the most-tested Linux distro for POWER7 architecture.
> >
> >IBM partnered with RedHat and Novell to make sure RHEL6 and SLES11 SP1 are
> >well tested with POWER7. Essential back-ports and bug are included in
> ^ bug _fixes_
>
> We try really hard to not add essential bugs ;).
LOL, indeed.
Mikey
^ permalink raw reply
* [PATCH v3 4/4] mmc: sdhci: merge two sdhci-pltfm.h into one
From: Shawn Guo @ 2011-05-25 11:01 UTC (permalink / raw)
To: linux-mmc
Cc: Shawn Guo, sameo, Arnd Bergmann, patches, devicetree-discuss,
Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1306321314-2493-1-git-send-email-shawn.guo@linaro.org>
The structure sdhci_pltfm_data is not necessarily to be in a public
header like include/linux/mmc/sdhci-pltfm.h, so the patch moves it
into drivers/mmc/host/sdhci-pltfm.h and eliminates the former one.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mmc/host/sdhci-cns3xxx.c | 1 -
drivers/mmc/host/sdhci-esdhc-imx.c | 1 -
drivers/mmc/host/sdhci-pltfm.h | 6 +++++-
include/linux/mmc/sdhci-pltfm.h | 29 -----------------------------
4 files changed, 5 insertions(+), 32 deletions(-)
delete mode 100644 include/linux/mmc/sdhci-pltfm.h
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index ac4b26f..025d1a5 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -15,7 +15,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
#include <mach/cns3xxx.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index e27ccbb..977f142 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -18,7 +18,6 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-pltfm.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <mach/hardware.h>
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index fe27b83..fd72694 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -14,9 +14,13 @@
#include <linux/clk.h>
#include <linux/types.h>
#include <linux/platform_device.h>
-#include <linux/mmc/sdhci-pltfm.h>
#include <linux/mmc/sdhci.h>
+struct sdhci_pltfm_data {
+ struct sdhci_ops *ops;
+ unsigned int quirks;
+};
+
struct sdhci_pltfm_host {
struct clk *clk;
void *priv; /* to handle quirks across io-accessor calls */
diff --git a/include/linux/mmc/sdhci-pltfm.h b/include/linux/mmc/sdhci-pltfm.h
deleted file mode 100644
index f1c2ac3..0000000
--- a/include/linux/mmc/sdhci-pltfm.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Platform data declarations for the sdhci-pltfm driver.
- *
- * Copyright (c) 2010 MontaVista Software, LLC.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#ifndef _SDHCI_PLTFM_H
-#define _SDHCI_PLTFM_H
-
-struct sdhci_ops;
-
-/**
- * struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
- * @ops: optional pointer to the platform-provided SDHCI ops
- * @quirks: optional SDHCI quirks
- */
-struct sdhci_pltfm_data {
- struct sdhci_ops *ops;
- unsigned int quirks;
-};
-
-#endif /* _SDHCI_PLTFM_H */
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 3/4] mmc: sdhci: make sdhci-of device drivers self registered
From: Shawn Guo @ 2011-05-25 11:01 UTC (permalink / raw)
To: linux-mmc
Cc: Shawn Guo, sameo, Arnd Bergmann, patches, devicetree-discuss,
Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1306321314-2493-1-git-send-email-shawn.guo@linaro.org>
The patch turns the sdhci-of-core common stuff into helper functions
added into sdhci-pltfm.c, and makes sdhci-of device drviers self
registered using the same pair of .probe and .remove used by
sdhci-pltfm device drivers.
As a result, sdhci-of-core.c and sdhci-of.h can be eliminated with
those common things merged into sdhci-pltfm.c and sdhci-pltfm.h
respectively.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/mmc/host/Kconfig | 15 +--
drivers/mmc/host/Makefile | 7 +-
drivers/mmc/host/sdhci-of-core.c | 251 -------------------------------------
drivers/mmc/host/sdhci-of-esdhc.c | 53 ++++++++-
drivers/mmc/host/sdhci-of-hlwd.c | 50 +++++++-
drivers/mmc/host/sdhci-of.h | 33 -----
drivers/mmc/host/sdhci-pltfm.c | 111 ++++++++++++++++-
drivers/mmc/host/sdhci-pltfm.h | 12 ++
8 files changed, 227 insertions(+), 305 deletions(-)
delete mode 100644 drivers/mmc/host/sdhci-of-core.c
delete mode 100644 drivers/mmc/host/sdhci-of.h
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 799e935..fdd20ad 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -81,19 +81,11 @@ config MMC_RICOH_MMC
If unsure, say Y.
-config MMC_SDHCI_OF
- tristate "SDHCI support on OpenFirmware platforms"
- depends on MMC_SDHCI && OF
- help
- This selects the OF support for Secure Digital Host Controller
- Interfaces.
-
- If unsure, say N.
-
config MMC_SDHCI_OF_ESDHC
bool "SDHCI OF support for the Freescale eSDHC controller"
- depends on MMC_SDHCI_OF
+ depends on MMC_SDHCI
depends on PPC_OF
+ select MMC_SDHCI_PLTFM
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help
This selects the Freescale eSDHC controller support.
@@ -102,8 +94,9 @@ config MMC_SDHCI_OF_ESDHC
config MMC_SDHCI_OF_HLWD
bool "SDHCI OF support for the Nintendo Wii SDHCI controllers"
- depends on MMC_SDHCI_OF
+ depends on MMC_SDHCI
depends on PPC_OF
+ select MMC_SDHCI_PLTFM
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help
This selects the Secure Digital Host Controller Interface (SDHCI)
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 95fddb8..01d38a1 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,11 +48,8 @@ obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
-
-obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
-sdhci-of-y := sdhci-of-core.o
-sdhci-of-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
-sdhci-of-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
+obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
deleted file mode 100644
index bca7062..0000000
--- a/drivers/mmc/host/sdhci-of-core.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * OpenFirmware bindings for Secure Digital Host Controller Interface.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/mmc/host.h>
-#ifdef CONFIG_PPC
-#include <asm/machdep.h>
-#endif
-#include "sdhci-of.h"
-#include "sdhci.h"
-
-#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
-
-/*
- * These accessors are designed for big endian hosts doing I/O to
- * little endian controllers incorporating a 32-bit hardware byte swapper.
- */
-
-u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
-{
- return in_be32(host->ioaddr + reg);
-}
-
-u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
-{
- return in_be16(host->ioaddr + (reg ^ 0x2));
-}
-
-u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
-{
- return in_8(host->ioaddr + (reg ^ 0x3));
-}
-
-void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
-{
- out_be32(host->ioaddr + reg, val);
-}
-
-void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- int base = reg & ~0x3;
- int shift = (reg & 0x2) * 8;
-
- switch (reg) {
- case SDHCI_TRANSFER_MODE:
- /*
- * Postpone this write, we must do it together with a
- * command write that is down below.
- */
- pltfm_host->xfer_mode_shadow = val;
- return;
- case SDHCI_COMMAND:
- sdhci_be32bs_writel(host,
- val << 16 | pltfm_host->xfer_mode_shadow,
- SDHCI_TRANSFER_MODE);
- return;
- }
- clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
-}
-
-void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- int base = reg & ~0x3;
- int shift = (reg & 0x3) * 8;
-
- clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
-}
-#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
-
-#ifdef CONFIG_PM
-
-static int sdhci_of_suspend(struct platform_device *ofdev, pm_message_t state)
-{
- struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
- return mmc_suspend_host(host->mmc);
-}
-
-static int sdhci_of_resume(struct platform_device *ofdev)
-{
- struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
- return mmc_resume_host(host->mmc);
-}
-
-#else
-
-#define sdhci_of_suspend NULL
-#define sdhci_of_resume NULL
-
-#endif
-
-static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
-{
- if (of_get_property(np, "sdhci,wp-inverted", NULL))
- return true;
-
- /* Old device trees don't have the wp-inverted property. */
-#ifdef CONFIG_PPC
- return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
-#else
- return false;
-#endif
-}
-
-static int __devinit sdhci_of_probe(struct platform_device *ofdev)
-{
- struct device_node *np = ofdev->dev.of_node;
- struct sdhci_pltfm_data *pdata;
- struct sdhci_host *host;
- struct sdhci_of_host *of_host;
- const __be32 *clk;
- int size;
- int ret;
-
- if (!ofdev->dev.of_match)
- return -EINVAL;
- pdata = ofdev->dev.of_match->data;
-
- if (!of_device_is_available(np))
- return -ENODEV;
-
- host = sdhci_alloc_host(&ofdev->dev, sizeof(*pltfm_host));
- if (IS_ERR(host))
- return -ENOMEM;
-
- pltfm_host = sdhci_priv(host);
- dev_set_drvdata(&ofdev->dev, host);
-
- host->ioaddr = of_iomap(np, 0);
- if (!host->ioaddr) {
- ret = -ENOMEM;
- goto err_addr_map;
- }
-
- host->irq = irq_of_parse_and_map(np, 0);
- if (!host->irq) {
- ret = -EINVAL;
- goto err_no_irq;
- }
-
- host->hw_name = dev_name(&ofdev->dev);
- if (pdata) {
- host->quirks = pdata->quirks;
- host->ops = &pdata->ops;
- }
-
- if (of_get_property(np, "sdhci,auto-cmd12", NULL))
- host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
-
-
- if (of_get_property(np, "sdhci,1-bit-only", NULL))
- host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
-
- if (sdhci_of_wp_inverted(np))
- host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
-
- clk = of_get_property(np, "clock-frequency", &size);
- if (clk && size == sizeof(*clk) && *clk)
- pltfm_host->clock = be32_to_cpup(clk);
-
- ret = sdhci_add_host(host);
- if (ret)
- goto err_add_host;
-
- return 0;
-
-err_add_host:
- irq_dispose_mapping(host->irq);
-err_no_irq:
- iounmap(host->ioaddr);
-err_addr_map:
- sdhci_free_host(host);
- return ret;
-}
-
-static int __devexit sdhci_of_remove(struct platform_device *ofdev)
-{
- struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
-
- sdhci_remove_host(host, 0);
- sdhci_free_host(host);
- irq_dispose_mapping(host->irq);
- iounmap(host->ioaddr);
- return 0;
-}
-
-static const struct of_device_id sdhci_of_match[] = {
-#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
- { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc_pdata, },
- { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc_pdata, },
- { .compatible = "fsl,esdhc", .data = &sdhci_esdhc_pdata, },
-#endif
-#ifdef CONFIG_MMC_SDHCI_OF_HLWD
- { .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd_pdata, },
-#endif
- { .compatible = "generic-sdhci", },
- {},
-};
-MODULE_DEVICE_TABLE(of, sdhci_of_match);
-
-static struct platform_driver sdhci_of_driver = {
- .driver = {
- .name = "sdhci-of",
- .owner = THIS_MODULE,
- .of_match_table = sdhci_of_match,
- },
- .probe = sdhci_of_probe,
- .remove = __devexit_p(sdhci_of_remove),
- .suspend = sdhci_of_suspend,
- .resume = sdhci_of_resume,
-};
-
-static int __init sdhci_of_init(void)
-{
- return platform_driver_register(&sdhci_of_driver);
-}
-module_init(sdhci_of_init);
-
-static void __exit sdhci_of_exit(void)
-{
- platform_driver_unregister(&sdhci_of_driver);
-}
-module_exit(sdhci_of_exit);
-
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface OF driver");
-MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
- "Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 492bcd7..2db6a45 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/mmc/host.h>
-#include "sdhci-of.h"
+#include "sdhci-pltfm.h"
#include "sdhci.h"
#include "sdhci-esdhc.h"
@@ -85,9 +85,58 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_min_clock = esdhc_of_get_min_clock,
};
-struct sdhci_pltfm_data sdhci_esdhc_pdata = {
+static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
/* card detection could be handled via GPIO */
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
| SDHCI_QUIRK_NO_CARD_NO_RESET,
.ops = &sdhci_esdhc_ops,
};
+
+static int __devinit sdhci_esdhc_probe(struct platform_device *pdev)
+{
+ return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
+}
+
+static int __devexit sdhci_esdhc_remove(struct platform_device *pdev)
+{
+ return sdhci_pltfm_unregister(pdev);
+}
+
+static const struct of_device_id sdhci_esdhc_of_match[] = {
+ { .compatible = "fsl,mpc8379-esdhc" },
+ { .compatible = "fsl,mpc8536-esdhc" },
+ { .compatible = "fsl,esdhc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
+
+static struct platform_driver sdhci_esdhc_driver = {
+ .driver = {
+ .name = "sdhci-esdhc",
+ .owner = THIS_MODULE,
+ .of_match_table = sdhci_esdhc_of_match,
+ },
+ .probe = sdhci_esdhc_probe,
+ .remove = __devexit_p(sdhci_esdhc_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_esdhc_init(void)
+{
+ return platform_driver_register(&sdhci_esdhc_driver);
+}
+module_init(sdhci_esdhc_init);
+
+static void __exit sdhci_esdhc_exit(void)
+{
+ platform_driver_unregister(&sdhci_esdhc_driver);
+}
+module_exit(sdhci_esdhc_exit);
+
+MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
+MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
+ "Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 380e896..faedfce 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -21,7 +21,7 @@
#include <linux/delay.h>
#include <linux/mmc/host.h>
-#include "sdhci-of.h"
+#include "sdhci-pltfm.h"
#include "sdhci.h"
/*
@@ -60,8 +60,54 @@ static struct sdhci_ops sdhci_hlwd_ops = {
.write_b = sdhci_hlwd_writeb,
};
-struct sdhci_pltfm_data sdhci_hlwd_pdata = {
+static struct sdhci_pltfm_data sdhci_hlwd_pdata = {
.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_32BIT_DMA_SIZE,
.ops = &sdhci_hlwd_ops,
};
+
+static int __devinit sdhci_hlwd_probe(struct platform_device *pdev)
+{
+ return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata);
+}
+
+static int __devexit sdhci_hlwd_remove(struct platform_device *pdev)
+{
+ return sdhci_pltfm_unregister(pdev);
+}
+
+static const struct of_device_id sdhci_hlwd_of_match[] = {
+ { .compatible = "nintendo,hollywood-sdhci" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match);
+
+static struct platform_driver sdhci_hlwd_driver = {
+ .driver = {
+ .name = "sdhci-hlwd",
+ .owner = THIS_MODULE,
+ .of_match_table = sdhci_hlwd_of_match,
+ },
+ .probe = sdhci_hlwd_probe,
+ .remove = __devexit_p(sdhci_hlwd_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_hlwd_init(void)
+{
+ return platform_driver_register(&sdhci_hlwd_driver);
+}
+module_init(sdhci_hlwd_init);
+
+static void __exit sdhci_hlwd_exit(void)
+{
+ platform_driver_unregister(&sdhci_hlwd_driver);
+}
+module_exit(sdhci_hlwd_exit);
+
+MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver");
+MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
deleted file mode 100644
index 5bdb5e7..0000000
--- a/drivers/mmc/host/sdhci-of.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * OpenFirmware bindings for Secure Digital Host Controller Interface.
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#ifndef __SDHCI_OF_H
-#define __SDHCI_OF_H
-
-#include <linux/types.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-
-extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
-extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
-extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
-extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
-extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
-extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
-
-extern struct sdhci_pltfm_data sdhci_esdhc_pdata;
-extern struct sdhci_pltfm_data sdhci_hlwd_pdata;
-
-#endif /* __SDHCI_OF_H */
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 8ccf256..041b0e2 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -2,6 +2,12 @@
* sdhci-pltfm.c Support for SDHCI platform devices
* Copyright (c) 2009 Intel Corporation
*
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ *
+ * Authors: Xiaobo Xie <X.Xie@freescale.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -23,13 +29,114 @@
*/
#include <linux/err.h>
-
+#include <linux/of.h>
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif
#include "sdhci.h"
#include "sdhci-pltfm.h"
static struct sdhci_ops sdhci_pltfm_ops = {
};
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+/*
+ * These accessors are designed for big endian hosts doing I/O to
+ * little endian controllers incorporating a 32-bit hardware byte swapper.
+ */
+u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
+{
+ return in_be32(host->ioaddr + reg);
+}
+
+u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
+{
+ return in_be16(host->ioaddr + (reg ^ 0x2));
+}
+
+u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
+{
+ return in_8(host->ioaddr + (reg ^ 0x3));
+}
+
+void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ out_be32(host->ioaddr + reg, val);
+}
+
+void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ int base = reg & ~0x3;
+ int shift = (reg & 0x2) * 8;
+
+ switch (reg) {
+ case SDHCI_TRANSFER_MODE:
+ /*
+ * Postpone this write, we must do it together with a
+ * command write that is down below.
+ */
+ pltfm_host->xfer_mode_shadow = val;
+ return;
+ case SDHCI_COMMAND:
+ sdhci_be32bs_writel(host,
+ val << 16 | pltfm_host->xfer_mode_shadow,
+ SDHCI_TRANSFER_MODE);
+ return;
+ }
+ clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
+}
+
+void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+ int base = reg & ~0x3;
+ int shift = (reg & 0x3) * 8;
+
+ clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
+}
+#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
+
+#ifdef CONFIG_OF
+static bool sdhci_of_wp_inverted(struct device_node *np)
+{
+ if (of_get_property(np, "sdhci,wp-inverted", NULL))
+ return true;
+
+ /* Old device trees don't have the wp-inverted property. */
+#ifdef CONFIG_PPC
+ return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
+#else
+ return false;
+#endif /* CONFIG_PPC */
+}
+
+void sdhci_get_of_property(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ const __be32 *clk;
+ int size;
+
+ if (of_device_is_available(np)) {
+ if (of_get_property(np, "sdhci,auto-cmd12", NULL))
+ host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+
+ if (of_get_property(np, "sdhci,1-bit-only", NULL))
+ host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
+
+ if (sdhci_of_wp_inverted(np))
+ host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+
+ clk = of_get_property(np, "clock-frequency", &size);
+ if (clk && size == sizeof(*clk) && *clk)
+ pltfm_host->clock = be32_to_cpup(clk);
+ }
+}
+#else
+void sdhci_get_of_property(struct platform_device *pdev) {}
+#endif /* CONFIG_OF */
+
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata)
{
@@ -117,6 +224,8 @@ int sdhci_pltfm_register(struct platform_device *pdev,
if (IS_ERR(host))
return PTR_ERR(host);
+ sdhci_get_of_property(pdev);
+
ret = sdhci_add_host(host);
if (ret)
sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 3cac450..fe27b83 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/mmc/sdhci-pltfm.h>
+#include <linux/mmc/sdhci.h>
struct sdhci_pltfm_host {
struct clk *clk;
@@ -25,6 +26,17 @@ struct sdhci_pltfm_host {
u16 xfer_mode_shadow;
};
+#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
+extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
+extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
+extern u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg);
+extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
+extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
+extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
+#endif
+
+extern void sdhci_get_of_property(struct platform_device *pdev);
+
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata);
extern void sdhci_pltfm_free(struct platform_device *pdev);
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 2/4] mmc: sdhci: eliminate sdhci_of_host and sdhci_of_data
From: Shawn Guo @ 2011-05-25 11:01 UTC (permalink / raw)
To: linux-mmc
Cc: Shawn Guo, sameo, Arnd Bergmann, patches, devicetree-discuss,
Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1306321314-2493-1-git-send-email-shawn.guo@linaro.org>
The patch migrates the use of sdhci_of_host and sdhci_of_data to
sdhci_pltfm_host and sdhci_pltfm_data, so that the former pair can
be eliminated.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
drivers/mmc/host/sdhci-of-core.c | 31 ++++++++++++++++---------------
drivers/mmc/host/sdhci-of-esdhc.c | 36 +++++++++++++++++++-----------------
drivers/mmc/host/sdhci-of-hlwd.c | 20 +++++++++++---------
drivers/mmc/host/sdhci-of.h | 15 +++------------
drivers/mmc/host/sdhci-pltfm.h | 4 ++++
5 files changed, 53 insertions(+), 53 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
index f9b611f..bca7062 100644
--- a/drivers/mmc/host/sdhci-of-core.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -59,7 +59,7 @@ void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg)
void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
{
- struct sdhci_of_host *of_host = sdhci_priv(host);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int base = reg & ~0x3;
int shift = (reg & 0x2) * 8;
@@ -69,10 +69,11 @@ void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg)
* Postpone this write, we must do it together with a
* command write that is down below.
*/
- of_host->xfer_mode_shadow = val;
+ pltfm_host->xfer_mode_shadow = val;
return;
case SDHCI_COMMAND:
- sdhci_be32bs_writel(host, val << 16 | of_host->xfer_mode_shadow,
+ sdhci_be32bs_writel(host,
+ val << 16 | pltfm_host->xfer_mode_shadow,
SDHCI_TRANSFER_MODE);
return;
}
@@ -127,7 +128,7 @@ static bool __devinit sdhci_of_wp_inverted(struct device_node *np)
static int __devinit sdhci_of_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
- struct sdhci_of_data *sdhci_of_data;
+ struct sdhci_pltfm_data *pdata;
struct sdhci_host *host;
struct sdhci_of_host *of_host;
const __be32 *clk;
@@ -136,16 +137,16 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
if (!ofdev->dev.of_match)
return -EINVAL;
- sdhci_of_data = ofdev->dev.of_match->data;
+ pdata = ofdev->dev.of_match->data;
if (!of_device_is_available(np))
return -ENODEV;
- host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host));
+ host = sdhci_alloc_host(&ofdev->dev, sizeof(*pltfm_host));
if (IS_ERR(host))
return -ENOMEM;
- of_host = sdhci_priv(host);
+ pltfm_host = sdhci_priv(host);
dev_set_drvdata(&ofdev->dev, host);
host->ioaddr = of_iomap(np, 0);
@@ -161,9 +162,9 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
}
host->hw_name = dev_name(&ofdev->dev);
- if (sdhci_of_data) {
- host->quirks = sdhci_of_data->quirks;
- host->ops = &sdhci_of_data->ops;
+ if (pdata) {
+ host->quirks = pdata->quirks;
+ host->ops = &pdata->ops;
}
if (of_get_property(np, "sdhci,auto-cmd12", NULL))
@@ -178,7 +179,7 @@ static int __devinit sdhci_of_probe(struct platform_device *ofdev)
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
- of_host->clock = be32_to_cpup(clk);
+ pltfm_host->clock = be32_to_cpup(clk);
ret = sdhci_add_host(host);
if (ret)
@@ -208,12 +209,12 @@ static int __devexit sdhci_of_remove(struct platform_device *ofdev)
static const struct of_device_id sdhci_of_match[] = {
#ifdef CONFIG_MMC_SDHCI_OF_ESDHC
- { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc, },
- { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc, },
- { .compatible = "fsl,esdhc", .data = &sdhci_esdhc, },
+ { .compatible = "fsl,mpc8379-esdhc", .data = &sdhci_esdhc_pdata, },
+ { .compatible = "fsl,mpc8536-esdhc", .data = &sdhci_esdhc_pdata, },
+ { .compatible = "fsl,esdhc", .data = &sdhci_esdhc_pdata, },
#endif
#ifdef CONFIG_MMC_SDHCI_OF_HLWD
- { .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd, },
+ { .compatible = "nintendo,hollywood-sdhci", .data = &sdhci_hlwd_pdata, },
#endif
{ .compatible = "generic-sdhci", },
{},
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index ba40d6d..492bcd7 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -60,32 +60,34 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
{
- struct sdhci_of_host *of_host = sdhci_priv(host);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- return of_host->clock;
+ return pltfm_host->clock;
}
static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
{
- struct sdhci_of_host *of_host = sdhci_priv(host);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- return of_host->clock / 256 / 16;
+ return pltfm_host->clock / 256 / 16;
}
-struct sdhci_of_data sdhci_esdhc = {
+static struct sdhci_ops sdhci_esdhc_ops = {
+ .read_l = sdhci_be32bs_readl,
+ .read_w = esdhc_readw,
+ .read_b = sdhci_be32bs_readb,
+ .write_l = sdhci_be32bs_writel,
+ .write_w = esdhc_writew,
+ .write_b = esdhc_writeb,
+ .set_clock = esdhc_set_clock,
+ .enable_dma = esdhc_of_enable_dma,
+ .get_max_clock = esdhc_of_get_max_clock,
+ .get_min_clock = esdhc_of_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_pdata = {
/* card detection could be handled via GPIO */
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
| SDHCI_QUIRK_NO_CARD_NO_RESET,
- .ops = {
- .read_l = sdhci_be32bs_readl,
- .read_w = esdhc_readw,
- .read_b = sdhci_be32bs_readb,
- .write_l = sdhci_be32bs_writel,
- .write_w = esdhc_writew,
- .write_b = esdhc_writeb,
- .set_clock = esdhc_set_clock,
- .enable_dma = esdhc_of_enable_dma,
- .get_max_clock = esdhc_of_get_max_clock,
- .get_min_clock = esdhc_of_get_min_clock,
- },
+ .ops = &sdhci_esdhc_ops,
};
diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
index 68ddb75..380e896 100644
--- a/drivers/mmc/host/sdhci-of-hlwd.c
+++ b/drivers/mmc/host/sdhci-of-hlwd.c
@@ -51,15 +51,17 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
udelay(SDHCI_HLWD_WRITE_DELAY);
}
-struct sdhci_of_data sdhci_hlwd = {
+static struct sdhci_ops sdhci_hlwd_ops = {
+ .read_l = sdhci_be32bs_readl,
+ .read_w = sdhci_be32bs_readw,
+ .read_b = sdhci_be32bs_readb,
+ .write_l = sdhci_hlwd_writel,
+ .write_w = sdhci_hlwd_writew,
+ .write_b = sdhci_hlwd_writeb,
+};
+
+struct sdhci_pltfm_data sdhci_hlwd_pdata = {
.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_32BIT_DMA_SIZE,
- .ops = {
- .read_l = sdhci_be32bs_readl,
- .read_w = sdhci_be32bs_readw,
- .read_b = sdhci_be32bs_readb,
- .write_l = sdhci_hlwd_writel,
- .write_w = sdhci_hlwd_writew,
- .write_b = sdhci_hlwd_writeb,
- },
+ .ops = &sdhci_hlwd_ops,
};
diff --git a/drivers/mmc/host/sdhci-of.h b/drivers/mmc/host/sdhci-of.h
index ad09ad9..5bdb5e7 100644
--- a/drivers/mmc/host/sdhci-of.h
+++ b/drivers/mmc/host/sdhci-of.h
@@ -18,16 +18,7 @@
#include <linux/types.h>
#include "sdhci.h"
-
-struct sdhci_of_data {
- unsigned int quirks;
- struct sdhci_ops ops;
-};
-
-struct sdhci_of_host {
- unsigned int clock;
- u16 xfer_mode_shadow;
-};
+#include "sdhci-pltfm.h"
extern u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg);
extern u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg);
@@ -36,7 +27,7 @@ extern void sdhci_be32bs_writel(struct sdhci_host *host, u32 val, int reg);
extern void sdhci_be32bs_writew(struct sdhci_host *host, u16 val, int reg);
extern void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg);
-extern struct sdhci_of_data sdhci_esdhc;
-extern struct sdhci_of_data sdhci_hlwd;
+extern struct sdhci_pltfm_data sdhci_esdhc_pdata;
+extern struct sdhci_pltfm_data sdhci_hlwd_pdata;
#endif /* __SDHCI_OF_H */
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index ff4b7eb..3cac450 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -19,6 +19,10 @@
struct sdhci_pltfm_host {
struct clk *clk;
void *priv; /* to handle quirks across io-accessor calls */
+
+ /* migrate from sdhci_of_host */
+ unsigned int clock;
+ u16 xfer_mode_shadow;
};
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 1/4] mmc: sdhci: make sdhci-pltfm device drivers self registered
From: Shawn Guo @ 2011-05-25 11:01 UTC (permalink / raw)
To: linux-mmc
Cc: Shawn Guo, sameo, Arnd Bergmann, patches, devicetree-discuss,
Saeed Bishara, Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson,
Chris Ball, linuxppc-dev, Albert Herranz, linux-arm-kernel
In-Reply-To: <1306321314-2493-1-git-send-email-shawn.guo@linaro.org>
The patch turns the common stuff in sdhci-pltfm.c into functions, and
add device drivers their own .probe and .remove which in turn call
into the common functions, so that those sdhci-pltfm device drivers
register itself and keep all device specific things away from common
sdhci-pltfm file.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
---
drivers/mmc/host/Kconfig | 32 ++++----
drivers/mmc/host/Makefile | 11 +--
drivers/mmc/host/sdhci-cns3xxx.c | 42 +++++++++-
drivers/mmc/host/sdhci-dove.c | 42 +++++++++-
drivers/mmc/host/sdhci-esdhc-imx.c | 113 +++++++++++++++++++-------
drivers/mmc/host/sdhci-pltfm.c | 157 +++++++++---------------------------
drivers/mmc/host/sdhci-pltfm.h | 17 +++-
drivers/mmc/host/sdhci-tegra.c | 116 ++++++++++++++++++--------
include/linux/mmc/sdhci-pltfm.h | 6 --
9 files changed, 317 insertions(+), 219 deletions(-)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b981715..799e935 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -113,28 +113,27 @@ config MMC_SDHCI_OF_HLWD
If unsure, say N.
config MMC_SDHCI_PLTFM
- tristate "SDHCI support on the platform specific bus"
+ bool
depends on MMC_SDHCI
help
- This selects the platform specific bus support for Secure Digital Host
- Controller Interface.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
+ This selects the platform common function support for Secure Digital
+ Host Controller Interface.
config MMC_SDHCI_CNS3XXX
- bool "SDHCI support on the Cavium Networks CNS3xxx SoC"
+ tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
depends on ARCH_CNS3XXX
- depends on MMC_SDHCI_PLTFM
+ depends on MMC_SDHCI
+ select MMC_SDHCI_PLTFM
help
This selects the SDHCI support for CNS3xxx System-on-Chip devices.
If unsure, say N.
config MMC_SDHCI_ESDHC_IMX
- bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
- depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
+ tristate "SDHCI platform support for the Freescale eSDHC i.MX controller"
+ depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5
+ depends on MMC_SDHCI
+ select MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Freescale eSDHC controller support on the platform
@@ -143,9 +142,10 @@ config MMC_SDHCI_ESDHC_IMX
If unsure, say N.
config MMC_SDHCI_DOVE
- bool "SDHCI support on Marvell's Dove SoC"
+ tristate "SDHCI support on Marvell's Dove SoC"
depends on ARCH_DOVE
- depends on MMC_SDHCI_PLTFM
+ depends on MMC_SDHCI
+ select MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Secure Digital Host Controller Interface in
@@ -154,8 +154,10 @@ config MMC_SDHCI_DOVE
If unsure, say N.
config MMC_SDHCI_TEGRA
- bool "SDHCI platform support for the Tegra SD/MMC Controller"
- depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
+ tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+ depends on ARCH_TEGRA
+ depends on MMC_SDHCI
+ select MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
This selects the Tegra SD/MMC controller. If you have a Tegra
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4f1df0a..95fddb8 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -43,12 +43,11 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_USHC) += ushc.o
-obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
-sdhci-platform-y := sdhci-pltfm.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
-sdhci-platform-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
+obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
+obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
+obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
+obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
+obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF) += sdhci-of.o
sdhci-of-y := sdhci-of-core.o
diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
index 9ebd1d7..ac4b26f 100644
--- a/drivers/mmc/host/sdhci-cns3xxx.c
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
@@ -86,7 +86,7 @@ static struct sdhci_ops sdhci_cns3xxx_ops = {
.set_clock = sdhci_cns3xxx_set_clock,
};
-struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
+static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
.ops = &sdhci_cns3xxx_ops,
.quirks = SDHCI_QUIRK_BROKEN_DMA |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@@ -95,3 +95,43 @@ struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_NONSTANDARD_CLOCK,
};
+
+static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev)
+{
+ return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
+}
+
+static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev)
+{
+ return sdhci_pltfm_unregister(pdev);
+}
+
+static struct platform_driver sdhci_cns3xxx_driver = {
+ .driver = {
+ .name = "sdhci-cns3xxx",
+ .owner = THIS_MODULE,
+ },
+ .probe = sdhci_cns3xxx_probe,
+ .remove = __devexit_p(sdhci_cns3xxx_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_cns3xxx_init(void)
+{
+ return platform_driver_register(&sdhci_cns3xxx_driver);
+}
+module_init(sdhci_cns3xxx_init);
+
+static void __exit sdhci_cns3xxx_exit(void)
+{
+ platform_driver_unregister(&sdhci_cns3xxx_driver);
+}
+module_exit(sdhci_cns3xxx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for CNS3xxx");
+MODULE_AUTHOR("Scott Shu, "
+ "Anton Vorontsov <avorontsov@mvista.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 2aeef4f..49aa533 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -61,10 +61,50 @@ static struct sdhci_ops sdhci_dove_ops = {
.read_l = sdhci_dove_readl,
};
-struct sdhci_pltfm_data sdhci_dove_pdata = {
+static struct sdhci_pltfm_data sdhci_dove_pdata = {
.ops = &sdhci_dove_ops,
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_FORCE_DMA,
};
+
+static int __devinit sdhci_dove_probe(struct platform_device *pdev)
+{
+ return sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+}
+
+static int __devexit sdhci_dove_remove(struct platform_device *pdev)
+{
+ return sdhci_pltfm_unregister(pdev);
+}
+
+static struct platform_driver sdhci_dove_driver = {
+ .driver = {
+ .name = "sdhci-dove",
+ .owner = THIS_MODULE,
+ },
+ .probe = sdhci_dove_probe,
+ .remove = __devexit_p(sdhci_dove_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
+};
+
+static int __init sdhci_dove_init(void)
+{
+ return platform_driver_register(&sdhci_dove_driver);
+}
+module_init(sdhci_dove_init);
+
+static void __exit sdhci_dove_exit(void)
+{
+ platform_driver_unregister(&sdhci_dove_driver);
+}
+module_exit(sdhci_dove_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Dove");
+MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, "
+ "Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a19967d..e27ccbb 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -191,16 +191,6 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
return clk_get_rate(pltfm_host->clk) / 256 / 16;
}
-static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
- struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
-
- if (boarddata && gpio_is_valid(boarddata->wp_gpio))
- return gpio_get_value(boarddata->wp_gpio);
- else
- return -ENOSYS;
-}
-
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le,
@@ -212,6 +202,24 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_min_clock = esdhc_pltfm_get_min_clock,
};
+static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+ .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
+ | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ /* ADMA has issues. Might be fixable */
+ .ops = &sdhci_esdhc_ops,
+};
+
+static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
+{
+ struct esdhc_platform_data *boarddata =
+ host->mmc->parent->platform_data;
+
+ if (boarddata && gpio_is_valid(boarddata->wp_gpio))
+ return gpio_get_value(boarddata->wp_gpio);
+ else
+ return -ENOSYS;
+}
+
static irqreturn_t cd_irq(int irq, void *data)
{
struct sdhci_host *sdhost = (struct sdhci_host *)data;
@@ -220,30 +228,35 @@ static irqreturn_t cd_irq(int irq, void *data)
return IRQ_HANDLED;
};
-static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_host *host;
+ struct esdhc_platform_data *boarddata;
struct clk *clk;
int err;
struct pltfm_imx_data *imx_data;
+ host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+
+ imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+ if (!imx_data)
+ return -ENOMEM;
+ pltfm_host->priv = imx_data;
+
clk = clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n");
- return PTR_ERR(clk);
+ err = PTR_ERR(clk);
+ goto err_clk_get;
}
clk_enable(clk);
pltfm_host->clk = clk;
- imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
- if (!imx_data) {
- clk_disable(pltfm_host->clk);
- clk_put(pltfm_host->clk);
- return -ENOMEM;
- }
- pltfm_host->priv = imx_data;
-
if (!cpu_is_mx25())
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -257,6 +270,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
+ boarddata = host->mmc->parent->platform_data;
if (boarddata) {
err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
if (err) {
@@ -289,6 +303,10 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
+ err = sdhci_add_host(host);
+ if (err)
+ goto err_add_host;
+
return 0;
no_card_detect_irq:
@@ -297,14 +315,23 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
boarddata->cd_gpio = err;
not_supported:
kfree(imx_data);
- return 0;
+ err_add_host:
+ clk_disable(pltfm_host->clk);
+ clk_put(pltfm_host->clk);
+ err_clk_get:
+ sdhci_pltfm_free(pdev);
+ return err;
}
-static void esdhc_pltfm_exit(struct sdhci_host *host)
+static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data;
struct pltfm_imx_data *imx_data = pltfm_host->priv;
+ int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+ sdhci_remove_host(host, dead);
if (boarddata && gpio_is_valid(boarddata->wp_gpio))
gpio_free(boarddata->wp_gpio);
@@ -319,13 +346,37 @@ static void esdhc_pltfm_exit(struct sdhci_host *host)
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
kfree(imx_data);
+
+ sdhci_pltfm_free(pdev);
+
+ return 0;
}
-struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA
- | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
- /* ADMA has issues. Might be fixable */
- .ops = &sdhci_esdhc_ops,
- .init = esdhc_pltfm_init,
- .exit = esdhc_pltfm_exit,
+static struct platform_driver sdhci_esdhc_imx_driver = {
+ .driver = {
+ .name = "sdhci-esdhc-imx",
+ .owner = THIS_MODULE,
+ },
+ .probe = sdhci_esdhc_imx_probe,
+ .remove = __devexit_p(sdhci_esdhc_imx_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
};
+
+static int __init sdhci_esdhc_imx_init(void)
+{
+ return platform_driver_register(&sdhci_esdhc_imx_driver);
+}
+module_init(sdhci_esdhc_imx_init);
+
+static void __exit sdhci_esdhc_imx_exit(void)
+{
+ platform_driver_unregister(&sdhci_esdhc_imx_driver);
+}
+module_exit(sdhci_esdhc_imx_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index dbab040..8ccf256 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -22,48 +22,22 @@
* Inspired by sdhci-pci.c, by Pierre Ossman
*/
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
-
-#include <linux/mmc/host.h>
-
-#include <linux/io.h>
-#include <linux/mmc/sdhci-pltfm.h>
+#include <linux/err.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
-/*****************************************************************************\
- * *
- * SDHCI core callbacks *
- * *
-\*****************************************************************************/
-
static struct sdhci_ops sdhci_pltfm_ops = {
};
-/*****************************************************************************\
- * *
- * Device probing/removal *
- * *
-\*****************************************************************************/
-
-static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
+struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
+ struct sdhci_pltfm_data *pdata)
{
- const struct platform_device_id *platid = platform_get_device_id(pdev);
- struct sdhci_pltfm_data *pdata;
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct resource *iomem;
int ret;
- if (platid && platid->driver_data)
- pdata = (void *)platid->driver_data;
- else
- pdata = pdev->dev.platform_data;
-
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
ret = -ENOMEM;
@@ -71,8 +45,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
}
if (resource_size(iomem) < 0x100)
- dev_err(&pdev->dev, "Invalid iomem size. You may "
- "experience problems.\n");
+ dev_err(&pdev->dev, "Invalid iomem size!\n");
/* Some PCI-based MFD need the parent here */
if (pdev->dev.parent != &platform_bus)
@@ -87,7 +60,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
- host->hw_name = "platform";
+ host->hw_name = dev_name(&pdev->dev);
if (pdata && pdata->ops)
host->ops = pdata->ops;
else
@@ -110,126 +83,70 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
goto err_remap;
}
- if (pdata && pdata->init) {
- ret = pdata->init(host, pdata);
- if (ret)
- goto err_plat_init;
- }
-
- ret = sdhci_add_host(host);
- if (ret)
- goto err_add_host;
-
platform_set_drvdata(pdev, host);
- return 0;
+ return host;
-err_add_host:
- if (pdata && pdata->exit)
- pdata->exit(host);
-err_plat_init:
- iounmap(host->ioaddr);
err_remap:
release_mem_region(iomem->start, resource_size(iomem));
err_request:
sdhci_free_host(host);
err:
- printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret);
- return ret;
+ dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
+ return ERR_PTR(ret);
}
-static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
+void sdhci_pltfm_free(struct platform_device *pdev)
{
- struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- int dead;
- u32 scratch;
-
- dead = 0;
- scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
- if (scratch == (u32)-1)
- dead = 1;
- sdhci_remove_host(host, dead);
- if (pdata && pdata->exit)
- pdata->exit(host);
iounmap(host->ioaddr);
release_mem_region(iomem->start, resource_size(iomem));
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
+}
- return 0;
+int sdhci_pltfm_register(struct platform_device *pdev,
+ struct sdhci_pltfm_data *pdata)
+{
+ struct sdhci_host *host;
+ int ret = 0;
+
+ host = sdhci_pltfm_init(pdev, pdata);
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ sdhci_pltfm_free(pdev);
+
+ return ret;
}
-static const struct platform_device_id sdhci_pltfm_ids[] = {
- { "sdhci", },
-#ifdef CONFIG_MMC_SDHCI_CNS3XXX
- { "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
- { "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_DOVE
- { "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata },
-#endif
-#ifdef CONFIG_MMC_SDHCI_TEGRA
- { "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata },
-#endif
- { },
-};
-MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
+int sdhci_pltfm_unregister(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+ sdhci_remove_host(host, dead);
+ sdhci_pltfm_free(pdev);
+
+ return 0;
+}
#ifdef CONFIG_PM
-static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
+int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_suspend_host(host, state);
}
-static int sdhci_pltfm_resume(struct platform_device *dev)
+int sdhci_pltfm_resume(struct platform_device *dev)
{
struct sdhci_host *host = platform_get_drvdata(dev);
return sdhci_resume_host(host);
}
-#else
-#define sdhci_pltfm_suspend NULL
-#define sdhci_pltfm_resume NULL
#endif /* CONFIG_PM */
-
-static struct platform_driver sdhci_pltfm_driver = {
- .driver = {
- .name = "sdhci",
- .owner = THIS_MODULE,
- },
- .probe = sdhci_pltfm_probe,
- .remove = __devexit_p(sdhci_pltfm_remove),
- .id_table = sdhci_pltfm_ids,
- .suspend = sdhci_pltfm_suspend,
- .resume = sdhci_pltfm_resume,
-};
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
- return platform_driver_register(&sdhci_pltfm_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
- platform_driver_unregister(&sdhci_pltfm_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
-MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 2b37016..ff4b7eb 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/types.h>
+#include <linux/platform_device.h>
#include <linux/mmc/sdhci-pltfm.h>
struct sdhci_pltfm_host {
@@ -20,9 +21,17 @@ struct sdhci_pltfm_host {
void *priv; /* to handle quirks across io-accessor calls */
};
-extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
-extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
-extern struct sdhci_pltfm_data sdhci_dove_pdata;
-extern struct sdhci_pltfm_data sdhci_tegra_pdata;
+extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
+ struct sdhci_pltfm_data *pdata);
+extern void sdhci_pltfm_free(struct platform_device *pdev);
+
+extern int sdhci_pltfm_register(struct platform_device *pdev,
+ struct sdhci_pltfm_data *pdata);
+extern int sdhci_pltfm_unregister(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+extern int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state);
+extern int sdhci_pltfm_resume(struct platform_device *dev);
+#endif
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 343c97e..1f66aca 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -116,20 +116,42 @@ static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
return 0;
}
+static struct sdhci_ops tegra_sdhci_ops = {
+ .get_ro = tegra_sdhci_get_ro,
+ .read_l = tegra_sdhci_readl,
+ .read_w = tegra_sdhci_readw,
+ .write_l = tegra_sdhci_writel,
+ .platform_8bit_width = tegra_sdhci_8bit,
+};
+
+static struct sdhci_pltfm_data sdhci_tegra_pdata = {
+ .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_NO_HISPD_BIT |
+ SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+ .ops = &tegra_sdhci_ops,
+};
-static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
- struct sdhci_pltfm_data *pdata)
+static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
+ struct sdhci_pltfm_host *pltfm_host;
struct tegra_sdhci_platform_data *plat;
+ struct sdhci_host *host;
struct clk *clk;
int rc;
+ host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ pltfm_host = sdhci_priv(host);
+
plat = pdev->dev.platform_data;
+
if (plat == NULL) {
dev_err(mmc_dev(host->mmc), "missing platform data\n");
- return -ENXIO;
+ rc = -ENXIO;
+ goto err_no_plat;
}
if (gpio_is_valid(plat->power_gpio)) {
@@ -137,7 +159,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (rc) {
dev_err(mmc_dev(host->mmc),
"failed to allocate power gpio\n");
- goto out;
+ goto err_power_req;
}
tegra_gpio_enable(plat->power_gpio);
gpio_direction_output(plat->power_gpio, 1);
@@ -148,7 +170,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (rc) {
dev_err(mmc_dev(host->mmc),
"failed to allocate cd gpio\n");
- goto out_power;
+ goto err_cd_req;
}
tegra_gpio_enable(plat->cd_gpio);
gpio_direction_input(plat->cd_gpio);
@@ -159,7 +181,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (rc) {
dev_err(mmc_dev(host->mmc), "request irq error\n");
- goto out_cd;
+ goto err_cd_irq_req;
}
}
@@ -169,7 +191,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (rc) {
dev_err(mmc_dev(host->mmc),
"failed to allocate wp gpio\n");
- goto out_irq;
+ goto err_wp_req;
}
tegra_gpio_enable(plat->wp_gpio);
gpio_direction_input(plat->wp_gpio);
@@ -179,7 +201,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n");
rc = PTR_ERR(clk);
- goto out_wp;
+ goto err_clk_get;
}
clk_enable(clk);
pltfm_host->clk = clk;
@@ -189,38 +211,47 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
if (plat->is_8bit)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+ rc = sdhci_add_host(host);
+ if (rc)
+ goto err_add_host;
+
return 0;
-out_wp:
+err_add_host:
+ clk_disable(pltfm_host->clk);
+ clk_put(pltfm_host->clk);
+err_clk_get:
if (gpio_is_valid(plat->wp_gpio)) {
tegra_gpio_disable(plat->wp_gpio);
gpio_free(plat->wp_gpio);
}
-
-out_irq:
+err_wp_req:
if (gpio_is_valid(plat->cd_gpio))
free_irq(gpio_to_irq(plat->cd_gpio), host);
-out_cd:
+err_cd_irq_req:
if (gpio_is_valid(plat->cd_gpio)) {
tegra_gpio_disable(plat->cd_gpio);
gpio_free(plat->cd_gpio);
}
-
-out_power:
+err_cd_req:
if (gpio_is_valid(plat->power_gpio)) {
tegra_gpio_disable(plat->power_gpio);
gpio_free(plat->power_gpio);
}
-
-out:
+err_power_req:
+err_no_plat:
+ sdhci_pltfm_free(pdev);
return rc;
}
-static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
+static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
struct tegra_sdhci_platform_data *plat;
+ int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+ sdhci_remove_host(host, dead);
plat = pdev->dev.platform_data;
@@ -242,22 +273,37 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host)
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
+
+ sdhci_pltfm_free(pdev);
+
+ return 0;
}
-static struct sdhci_ops tegra_sdhci_ops = {
- .get_ro = tegra_sdhci_get_ro,
- .read_l = tegra_sdhci_readl,
- .read_w = tegra_sdhci_readw,
- .write_l = tegra_sdhci_writel,
- .platform_8bit_width = tegra_sdhci_8bit,
+static struct platform_driver sdhci_tegra_driver = {
+ .driver = {
+ .name = "sdhci-tegra",
+ .owner = THIS_MODULE,
+ },
+ .probe = sdhci_tegra_probe,
+ .remove = __devexit_p(sdhci_tegra_remove),
+#ifdef CONFIG_PM
+ .suspend = sdhci_pltfm_suspend,
+ .resume = sdhci_pltfm_resume,
+#endif
};
-struct sdhci_pltfm_data sdhci_tegra_pdata = {
- .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_NO_HISPD_BIT |
- SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
- .ops = &tegra_sdhci_ops,
- .init = tegra_sdhci_pltfm_init,
- .exit = tegra_sdhci_pltfm_exit,
-};
+static int __init sdhci_tegra_init(void)
+{
+ return platform_driver_register(&sdhci_tegra_driver);
+}
+module_init(sdhci_tegra_init);
+
+static void __exit sdhci_tegra_exit(void)
+{
+ platform_driver_unregister(&sdhci_tegra_driver);
+}
+module_exit(sdhci_tegra_exit);
+
+MODULE_DESCRIPTION("SDHCI driver for Tegra");
+MODULE_AUTHOR(" Google, Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mmc/sdhci-pltfm.h b/include/linux/mmc/sdhci-pltfm.h
index 548d59d..f1c2ac3 100644
--- a/include/linux/mmc/sdhci-pltfm.h
+++ b/include/linux/mmc/sdhci-pltfm.h
@@ -15,21 +15,15 @@
#define _SDHCI_PLTFM_H
struct sdhci_ops;
-struct sdhci_host;
/**
* struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
* @ops: optional pointer to the platform-provided SDHCI ops
* @quirks: optional SDHCI quirks
- * @init: optional hook that is called during device probe, before the
- * driver tries to access any SDHCI registers
- * @exit: optional hook that is called during device removal
*/
struct sdhci_pltfm_data {
struct sdhci_ops *ops;
unsigned int quirks;
- int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
- void (*exit)(struct sdhci_host *host);
};
#endif /* _SDHCI_PLTFM_H */
--
1.7.4.1
^ permalink raw reply related
* [PATCH v3 0/4] Consolidate sdhci pltfm & OF drivers and get them self registered
From: Shawn Guo @ 2011-05-25 11:01 UTC (permalink / raw)
To: linux-mmc
Cc: sameo, Arnd Bergmann, patches, devicetree-discuss, Saeed Bishara,
Xiaobo Xie, kernel, Mike Rapoport, Olof Johansson, Chris Ball,
linuxppc-dev, Albert Herranz, linux-arm-kernel
Here are what the patch set does.
* Remove .probe and .remove hooks from sdhci-pltfm.c and make it be
a pure common helper function providers.
* Add .probe and .remove hooks for sdhci pltfm drivers sdhci-cns3xxx,
sdhci-dove, sdhci-tegra, and sdhci-esdhc-imx to make them self
registered with calling helper functions created above.
* Migrate the use of sdhci_of_host and sdhci_of_data to
sdhci_pltfm_host and sdhci_pltfm_data, so that OF version host and
data structure works can be saved, and pltfm version works for both
cases.
* Add OF common helper stuff into sdhci-pltfm.c, and make OF version
sdhci drivers sdhci-of-esdhc and sdhci-of-hlwd become self
registered as well, so that sdhci-of-core.c and sdhci-of.h can be
removed.
* Eliminate include/linux/mmc/sdhci-pltfm.h with moving stuff into
drivers/mmc/host/sdhci-pltfm.h.
And the benefits we gain from the changes are:
* Get the sdhci device driver follow the Linux trend that driver
makes the registration by its own.
* sdhci-pltfm.c becomes simple and clean as it only has common helper
stuff there now.
* All sdhci device specific things are going back its own driver.
* The dt and non-dt drivers are consolidated to use the same pair of
.probe and .remove hooks.
Changes since v2:
* Drop imx mpc esdhc consolidation
* Fix checkpatch errors
* Add sdhci-of-core.c copyright into sdhci-pltfm.c
Changes since v1:
* Rebase on cjb's mmc-next tree
* Introduce helper function pair sdhci_pltfm_register and
sdhci_pltfm_unregister
* Eliminate variable 'scratch' in .remove hook to make the code
look simple
* Return ERR_PTR in sdhci_pltfm_init and use IS_ERR/PTR_ERR to check
return value in .probe hooks
* Correct MODULE_AUTHOR statement
* Split esdhc conlidation patch to ease reviewing
Shawn Guo (4):
mmc: sdhci: make sdhci-pltfm device drivers self registered
mmc: sdhci: eliminate sdhci_of_host and sdhci_of_data
mmc: sdhci: make sdhci-of device drivers self registered
mmc: sdhci: merge two sdhci-pltfm.h into one
drivers/mmc/host/Kconfig | 47 +++----
drivers/mmc/host/Makefile | 18 +--
drivers/mmc/host/sdhci-cns3xxx.c | 43 ++++++-
drivers/mmc/host/sdhci-dove.c | 42 ++++++-
drivers/mmc/host/sdhci-esdhc-imx.c | 114 +++++++++++-----
drivers/mmc/host/sdhci-of-core.c | 250 ---------------------------------
drivers/mmc/host/sdhci-of-esdhc.c | 85 +++++++++---
drivers/mmc/host/sdhci-of-hlwd.c | 66 ++++++++--
drivers/mmc/host/sdhci-of.h | 42 ------
drivers/mmc/host/sdhci-pltfm.c | 266 ++++++++++++++++++++----------------
drivers/mmc/host/sdhci-pltfm.h | 39 +++++-
drivers/mmc/host/sdhci-tegra.c | 116 +++++++++++-----
include/linux/mmc/sdhci-pltfm.h | 35 -----
13 files changed, 578 insertions(+), 585 deletions(-)
Regards,
Shawn
^ permalink raw reply
* RE: Cannot run tcl program of PPC460EX
From: David Laight @ 2011-05-25 10:47 UTC (permalink / raw)
To: Josh Boyer, efti; +Cc: linuxppc-dev
In-Reply-To: <20110525104549.GC22207@zod.rchland.ibm.com>
=20
> On Tue, May 24, 2011 at 11:16:12PM -0700, efti wrote:
> >
> > I am trying to run tcl of my PPC460ex board. I have download the
> > tcl-8.3.3-sol26-sparc-local.gz file. But when I run it I get=20
> > the Syntax error.
>=20
> That tarball seems to indicate it's for both Solaris and Sparc.
> PPC460ex is neither of those.
Which may well mean that the 'syntax error' is from the shell
trying to interpret (as a shell script) a sparc elf binary
that the kernel has failed to 'exec'.
David
^ permalink raw reply
* Re: Kernel cannot see PCI device
From: Prashant Bhole @ 2011-05-25 10:48 UTC (permalink / raw)
To: Stefan Roese
Cc: Bjorn Helgaas, Tirumala Marri, linuxppc-dev,
linux-pci@vger.kernel.org
In-Reply-To: <201105251157.12537.sr@denx.de>
On Wed, May 25, 2011 at 3:27 PM, Stefan Roese <sr@denx.de> wrote:
> On Tuesday 24 May 2011 23:43:08 Benjamin Herrenschmidt wrote:
>> On Tue, 2011-05-24 at 10:25 +0530, Prashant Bhole wrote:
>> > Fixed the problem by soft resetting the PCIe port in the function
>> > ppc460ex_pciex_port_init_hw().
>> > Is it a right thing to do?
>
> <snip>
>
>> Well, it's odd that you'd have to do that, maybe something the
>> bootloader is doing ?
>>
>> I personally don't mind but I'd like Stefan and/or Tirumala opinion on
>> this.
>
> Not sure. I had no problems with the PCIe cards I tested with the current
> code. But from my experience, this card reset behavior is highly card/device
> dependent.
>
> It would be good to know that this new code doesn't break detection of other
> PCIe cards/devices. Prashant, did you check this new code with other PCIe
> cards/devices as well? If this patch doesn't break other PCIe cards like the
> Intel PRO/1000, then:
>
I agree, this behavior is device specific. I have other boards with
different disk
controller chips. Those chips were detected without soft resetting the port.
New code has been checked with three PCIe devices:
Marvell 88SE9485, SiI 3132 and LSISAS2008.
-Prashant
^ permalink raw reply
* Re: Cannot run tcl program of PPC460EX
From: Josh Boyer @ 2011-05-25 10:45 UTC (permalink / raw)
To: efti; +Cc: linuxppc-dev
In-Reply-To: <31696288.post@talk.nabble.com>
On Tue, May 24, 2011 at 11:16:12PM -0700, efti wrote:
>
>Hi,
>
>I am trying to run tcl of my PPC460ex board. I have download the
>tcl-8.3.3-sol26-sparc-local.gz file. But when I run it I get the Syntax
>error.
That tarball seems to indicate it's for both Solaris and Sparc.
PPC460ex is neither of those.
>I am not sure if I missed out something.
>
>I would really appreciate it if somebody could help me on this.
We'd need more information. Things like:
1) What kernel you are running
2) What userspace OS
3) The URL to the tcl you're downloading
4) The actual error message
josh
^ permalink raw reply
* Re: Best Linux choice for POWER7?
From: Josh Boyer @ 2011-05-25 10:43 UTC (permalink / raw)
To: Michael Neuling; +Cc: Gabriel Menini, linuxppc-dev
In-Reply-To: <452.1306288195@neuling.org>
On Wed, May 25, 2011 at 11:49:55AM +1000, Michael Neuling wrote:
>Gabriel,
>
>> I am looking for the most-tested Linux distro for POWER7 architecture.
>
>IBM partnered with RedHat and Novell to make sure RHEL6 and SLES11 SP1 are
>well tested with POWER7. Essential back-ports and bug are included in
^ bug _fixes_
We try really hard to not add essential bugs ;).
josh
^ permalink raw reply
* Re: [PATCH 3/5] v2 seccomp_filters: Enable ftrace-based system call filtering
From: Thomas Gleixner @ 2011-05-25 10:35 UTC (permalink / raw)
To: Ingo Molnar
Cc: linux-mips, linux-sh, Peter Zijlstra, Frederic Weisbecker,
Heiko Carstens, Oleg Nesterov, David Howells, Paul Mackerras,
Eric Paris, H. Peter Anvin, sparclinux, Jiri Slaby, linux-s390,
Russell King, x86, James Morris, Linus Torvalds, Ingo Molnar,
kees.cook, Serge E. Hallyn, Steven Rostedt, Martin Schwidefsky,
linux-arm-kernel, Michal Marek, Michal Simek, Will Drewry,
linuxppc-dev, linux-kernel, Ralf Baechle, Paul Mundt, Tejun Heo,
linux390, Andrew Morton, agl, David S. Miller
In-Reply-To: <20110524195435.GC27634@elte.hu>
On Tue, 24 May 2011, Ingo Molnar wrote:
> * Peter Zijlstra <peterz@infradead.org> wrote:
>
> > On Tue, 2011-05-24 at 10:59 -0500, Will Drewry wrote:
> > > include/linux/ftrace_event.h | 4 +-
> > > include/linux/perf_event.h | 10 +++++---
> > > kernel/perf_event.c | 49 +++++++++++++++++++++++++++++++++++++---
> > > kernel/seccomp.c | 8 ++++++
> > > kernel/trace/trace_syscalls.c | 27 +++++++++++++++++-----
> > > 5 files changed, 82 insertions(+), 16 deletions(-)
> >
> > I strongly oppose to the perf core being mixed with any sekurity voodoo
> > (or any other active role for that matter).
>
> I'd object to invisible side-effects as well, and vehemently so. But note how
> intelligently it's used here: it's explicit in the code, it's used explicitly
> in kernel/seccomp.c and the event generation place in
> kernel/trace/trace_syscalls.c.
>
> So this is a really flexible solution IMO and does not extend events with some
> invisible 'active' role. It extends the *call site* with an open-coded active
> role - which active role btw. already pre-existed.
We do _NOT_ make any decision based on the trace point so what's the
"pre-existing" active role in the syscall entry code?
I'm all for code reuse and reuse of interfaces, but this is completely
wrong. Instrumentation and security decisions are two fundamentally
different things and we want them kept separate. Instrumentation is
not meant to make decisions. Just because we can does not mean that it
is a good idea.
So what the current approach does is:
- abuse the existing ftrace syscall hook by adding a return value to
the tracepoint.
So we need to propagate that for every tracepoint just because we
have a single user.
- abuse the perf per task mechanism
Just because we have per task context in perf does not mean that we
pull everything and the world which requires per task context into
perf. The security folks have per task context already so security
related stuff wants to go there.
- abuse the perf/ftrace interfaces
One of the arguments was that perf and ftrace have permission which
are not available from the existing security interfaces. That's not
at all a good reason to abuse these interfaces. Let the security
folks sort out the problem on their end and do not impose any
expectations on perf/ftrace which we have to carry around forever.
Yes, it can be made working with a relatively small patch, but it has
a very nasty side effect:
You add another user space visible ABI to the existing perf/ftrace
mess which needs to be supported forever.
Brilliant, we have already two ABIs (perf/ftrace) to support and at
the same time we urgently need to solve the problem of better
integration of those two. So adding a third completely unrelated
component with a guaranteed ABI is just making this even more complex.
We can factor out the filtering code and let the security dudes reuse
it for their own purposes. That makes them to have their own
interfaces and does not impose any restrictions upon the tracing/perf
ones. And really security stuff wants to be integrated into the
existing security frameworks and not duct taped into perf/trace just
because it's a conveniant hack around limitiations of the existing
security stuff.
You really should stop to see everything as a nail just because the
only tool you have handy is the perf hammer. perf is about
instrumentation and we don't want to violate the oldest principle of
unix to have simple tools which do one thing and do it good.
Even swiss army knifes have the restriction that you can use only one
tool at a time unless you want to stick the corkscrew through your
palm when you try to cut bread.
Thanks,
tglx
^ permalink raw reply
* Re: Kernel cannot see PCI device
From: Stefan Roese @ 2011-05-25 9:57 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Bjorn Helgaas, linux-pci@vger.kernel.org, Prashant Bhole,
linuxppc-dev, Tirumala Marri
In-Reply-To: <1306273388.7481.240.camel@pasglop>
On Tuesday 24 May 2011 23:43:08 Benjamin Herrenschmidt wrote:
> On Tue, 2011-05-24 at 10:25 +0530, Prashant Bhole wrote:
> > Fixed the problem by soft resetting the PCIe port in the function
> > ppc460ex_pciex_port_init_hw().
> > Is it a right thing to do?
<snip>
> Well, it's odd that you'd have to do that, maybe something the
> bootloader is doing ?
>
> I personally don't mind but I'd like Stefan and/or Tirumala opinion on
> this.
Not sure. I had no problems with the PCIe cards I tested with the current
code. But from my experience, this card reset behavior is highly card/device
dependent.
It would be good to know that this new code doesn't break detection of other
PCIe cards/devices. Prashant, did you check this new code with other PCIe
cards/devices as well? If this patch doesn't break other PCIe cards like the
Intel PRO/1000, then:
Acked-by: Stefan Roese <sr@denx.de>
Cheers,
Stefan
^ permalink raw reply
* Re: [PATCH v2 5/7] mmc: sdhci: consolidate sdhci-of-esdhc and sdhci-esdhc-imx
From: Shawn Guo @ 2011-05-25 9:36 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: Chris Ball, Anton Vorontsov, sameo, Arnd Bergmann, patches,
devicetree-discuss, linux-mmc, Saeed Bishara, Xiaobo Xie, kernel,
Mike Rapoport, Olof Johansson, Shawn Guo, linuxppc-dev,
Albert Herranz, linux-arm-kernel
In-Reply-To: <20110525064619.GI9774@pengutronix.de>
Hi Uwe,
On Wed, May 25, 2011 at 08:46:19AM +0200, Uwe Kleine-K=F6nig wrote:
> Hello Shawn,
>=20
> > > > +#ifndef CONFIG_MMC_SDHCI_ESDHC_IMX
> > > > +#define cpu_is_mx25() (0)
> > > > +#define cpu_is_mx35() (0)
> > > > +#define cpu_is_mx51() (0)
> > > > +#define cpu_is_imx() (0)
> > > > +#else
> > > > +#define cpu_is_imx() (1)
> > > > +#endif
> > >=20
> > > ... e.g. that looks a bit frightening.
> > >=20
> > Agree.
> >=20
> > The use of cpu_is_mx..() in the driver itself seems a churn to me
> > even without this consolidation patch. Is it possible for us to
> > eliminate them by using pdata, and eventually device tree? When we
> > are there, I might want to revisit the consolidation again.
> An alternative that allows letting the logic in the driver and still
> getting rid of the cpu_is_ stuff is using platform ids. See
> drivers/spi/spi_imx.c for an example. Instead of an index into an array
> (as it's for the imx-spi driver) driver_data can hold flags, too, which
> should be enough most of the time.
>=20
Yeah, this is definitely a solution I can try later. But for now, I
would drop the esdhc consolidation patch.
--=20
Regards,
Shawn
^ permalink raw reply
* Re: [v5] powerpc: Force page alignment for initrd reserved memory
From: Milton Miller @ 2011-05-25 9:28 UTC (permalink / raw)
To: Dave Carroll; +Cc: LPPC, LKML
In-Reply-To: <522F24EF533FC546962ECFA2054FF777373072AB79@MAILSERVER2.cos.astekcorp.com>
On Mon, 23 May 2011 about 12:54:25 -0000, Dave Carroll wrote:
> When using 64K pages with a separate cpio rootfs, U-Boot will align
> the rootfs on a 4K page boundary. When the memory is reserved, and
> subsequent early memblock_alloc is called, it will allocate memory
> between the 64K page alignment and reserved memory. When the reserved
> memory is subsequently freed, it is done so by pages, causing the
> early memblock_alloc requests to be re-used, which in my case, caused
> the device-tree to be clobbered.
>
> This patch forces the reserved memory for initrd to be kernel page
> aligned, and adds the same range extension when freeing initrd. It
> will also move the device tree if it overlaps with the reserved memory
> for initrd.
>
> Many thanks to Milton Miller for his input on this patch.
>
> Signed-off-by: Dave Carroll <dcarroll@astekcorp.com>
>
> ---
> * This patch is based on Linus' current tree
Ben if I had reviewed this closely, so I tried to apply it. First
it failed because it arrived with
Content-Transfer-Encoding: quoted-printable
patchwork was nice enough to fix that, but it still didn't apply
because tabs were changed to spaces.
While both of those things can be fixed, It would reduce the burden
to test and apply if you can fix your mailer.
>
> arch/powerpc/kernel/prom.c | 11 ++++++++---
> arch/powerpc/mm/init_32.c | 5 ++++-
> arch/powerpc/mm/init_64.c | 5 ++++-
> 3 files changed, 16 insertions(+), 5 deletions(-)
>
> --
> 1.7.4
>
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index 48aeb55..58871df 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -86,7 +86,8 @@ early_param("mem", early_parse_mem);
> * move_device_tree - move tree to an unused area, if needed.
> *
> * The device tree may be allocated beyond our memory limit, or inside the
> - * crash kernel region for kdump. If so, move it out of the way.
> + * crash kernel region for kdump, or within the page aligned range of initrd.
> + * If so, move it out of the way.
> */
> static void __init move_device_tree(void)
> {
> @@ -99,7 +100,9 @@ static void __init move_device_tree(void)
> size = be32_to_cpu(initial_boot_params->totalsize);
>
> if ((memory_limit && (start + size) > PHYSICAL_START + memory_limit) ||
> - overlaps_crashkernel(start, size)) {
> + overlaps_crashkernel(start, size) ||
> + ((start + size) > _ALIGN_DOWN(initrd_start, PAGE_SIZE)
> + && start <= _ALIGN_UP(initrd_end, PAGE_SIZE))) {
When reviewing that with Ben, I thought the && should have been ||. But
upon further review and comparison with overlaps_crashkernel, I see &&
is correct; it checks both the end is after the start and start is after end.
But that does point out the expression is too complex to read. Please
create a helper overlaps_initrd similar to overlaps_crashkernel. In that
function you should also return false if initrd_start is 0.
> p = __va(memblock_alloc(size, PAGE_SIZE));
> memcpy(p, initial_boot_params, size);
> initial_boot_params = (struct boot_param_header *)p;
> @@ -555,7 +558,9 @@ static void __init early_reserve_mem(void)
> #ifdef CONFIG_BLK_DEV_INITRD
> /* then reserve the initrd, if any */
> if (initrd_start && (initrd_end > initrd_start))
> - memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
> + memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE),
> + _ALIGN_UP(initrd_end, PAGE_SIZE) -
> + _ALIGN_DOWN(initrd_start, PAGE_SIZE));
> #endif /* CONFIG_BLK_DEV_INITRD */
>
> #ifdef CONFIG_PPC32
> diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
> index d65b591..4835c4f 100644
> --- a/arch/powerpc/mm/init_32.c
> +++ b/arch/powerpc/mm/init_32.c
> @@ -226,8 +226,11 @@ void free_initmem(void)
> #ifdef CONFIG_BLK_DEV_INITRD
> void free_initrd_mem(unsigned long start, unsigned long end)
> {
> - if (start < end)
> + if (start < end) {
> + start = _ALIGN_DOWN(start, PAGE_SIZE);
> + end = _ALIGN_UP(end, PAGE_SIZE);
> printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
> + }
With the additional code added, Ben and I both noticed the indent
level can be reduced by reversing the condition and issuing an
early return. eg:
if (start >= end)
return;
This will also bring the printk line back under 80 columns.
> for (; start < end; start += PAGE_SIZE) {
> ClearPageReserved(virt_to_page(start));
> init_page_count(virt_to_page(start));
> diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
> index 6374b21..060c952 100644
> --- a/arch/powerpc/mm/init_64.c
> +++ b/arch/powerpc/mm/init_64.c
> @@ -102,8 +102,11 @@ void free_initmem(void)
> #ifdef CONFIG_BLK_DEV_INITRD
> void free_initrd_mem(unsigned long start, unsigned long end)
> {
> - if (start < end)
> + if (start < end) {
> + start = _ALIGN_DOWN(start, PAGE_SIZE);
> + end = _ALIGN_UP(end, PAGE_SIZE);
> printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
> + }
> for (; start < end; start += PAGE_SIZE) {
> ClearPageReserved(virt_to_page(start));
> init_page_count(virt_to_page(start));
Ben noticed the duplication and asked that the function be moved to
mem.c, which is common for 32 and 64 bit.
I would ask that, in addition, you prepare a second patch that
consolidates the free_initmem functions just above them by
noting that all sections except init were removed in v2.6.15 by
6c45ab992e4299c869fb26427944a8f8ea177024 (powerpc: Remove section
free() and linker script bits), and therefore the bulk of the executed
code is identical.
However, I see its a bit more involved because of that last line in
the 32 bit code which clears ppc_md.progress. A bit of research shows
we mostly don't call ppc_md.progress after init calls, but powermac
has a late initcall to clear it because they call it from a smp hook,
and the progress function is marked __init. Further research shows
most are marked init, including somewhat duplicated functions across
64 bit powerpc; the exception seems to be rtas_progress which is
called directly (not through ppc_md) from rtas-proc.c.
So upon further review, clear the ppc_md.progress to NULL at the
beginning of the consolidated function (before we start to release
the pages with the code). You can then remove the late_initcall in
the powermac code.
Extra credit to create and consolidate a printk_progress companion
to the udbg_progress call (but located somewhere common like
arch/powerpc/kernel/setup-common.c).
Thanks,
milton
^ permalink raw reply
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