* [PATCH v5 4/5] highbank: Unconditionally require l2x0 L2 cache controller support
From: Dave Martin @ 2011-12-15 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323964434-6764-1-git-send-email-dave.martin@linaro.org>
If running in the Normal World on a TrustZone-enabled SoC, Linux
does not have complete control over the L2 cache controller
configuration. The kernel cannot work reliably on such platforms
without the l2x0 cache support code built in.
This patch unconditionally enables l2x0 support for the Highbank
SoC.
Thanks to Rob Herring for this suggestion. [1]
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074495.html
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Rob Herring <rob.herring@calxeda.com>
---
arch/arm/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index eca82f9..1792146 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -340,12 +340,12 @@ config ARCH_HIGHBANK
select ARM_AMBA
select ARM_GIC
select ARM_TIMER_SP804
+ select CACHE_L2X0
select CLKDEV_LOOKUP
select CPU_V7
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
select HAVE_SMP
- select MIGHT_HAVE_CACHE_L2X0
select USE_OF
help
Support for the Calxeda Highbank SoC based boards.
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 3/5] omap4: Unconditionally require l2x0 L2 cache controller support
From: Dave Martin @ 2011-12-15 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323964434-6764-1-git-send-email-dave.martin@linaro.org>
If running in the Normal World on a TrustZone-enabled SoC, Linux
does not have complete control over the L2 cache controller
configuration. The kernel cannot work reliably on such platforms
without the l2x0 cache support code built in.
This patch unconditionally enables l2x0 support for the OMAP4 SoCs.
Thanks to Rob Herring for this suggestion. [1]
[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074495.html
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Tony Lindgren <tony@atomide.com>
---
arch/arm/mach-omap2/Kconfig | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index bb1b670..94e568a 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -41,11 +41,11 @@ config ARCH_OMAP4
bool "TI OMAP4"
default y
depends on ARCH_OMAP2PLUS
+ select CACHE_L2X0
select CPU_V7
select ARM_GIC
select HAVE_SMP
select LOCAL_TIMERS if SMP
- select MIGHT_HAVE_CACHE_L2X0
select PL310_ERRATA_588369
select PL310_ERRATA_727915
select ARM_ERRATA_720789
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 2/5] ARM: SMP: Refactor Kconfig to be more maintainable
From: Dave Martin @ 2011-12-15 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323964434-6764-1-git-send-email-dave.martin@linaro.org>
Making SMP depend on (huge list of MACH_ and ARCH_ configs) is
bothersome to maintain and likely to lead to merge conflicts.
This patch moves the knowledge of which platforms are SMP-capable
to the individual machines. To enable this, a new HAVE_SMP config
option is introduced to allow machines to indicate that they can
run in a SMP configuration.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
(for nomadik, ux500)
Acked-by: Tony Lindgren <tony@atomide.com>
(for omap)
---
Changes:
v5: Minor change to the Kconfig help text to make it more
informative.
arch/arm/Kconfig | 18 ++++++++++++++----
arch/arm/mach-exynos/Kconfig | 1 +
arch/arm/mach-imx/Kconfig | 1 +
arch/arm/mach-msm/Kconfig | 1 +
arch/arm/mach-omap2/Kconfig | 1 +
arch/arm/mach-realview/Kconfig | 4 ++++
arch/arm/mach-vexpress/Kconfig | 1 +
7 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 16a4b9e..eca82f9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -344,6 +344,7 @@ config ARCH_HIGHBANK
select CPU_V7
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select USE_OF
help
@@ -636,6 +637,7 @@ config ARCH_TEGRA
select GENERIC_GPIO
select HAVE_CLK
select HAVE_SCHED_CLOCK
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select ARCH_HAS_CPUFREQ
help
@@ -706,6 +708,7 @@ config ARCH_SHMOBILE
select HAVE_CLK
select CLKDEV_LOOKUP
select HAVE_MACH_CLKDEV
+ select HAVE_SMP
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_CACHE_L2X0
select NO_IOPORT
@@ -909,6 +912,7 @@ config ARCH_U8500
select CLKDEV_LOOKUP
select ARCH_REQUIRE_GPIOLIB
select ARCH_HAS_CPUFREQ
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
Support for ST-Ericsson's Ux500 architecture
@@ -1430,14 +1434,20 @@ menu "Kernel Features"
source "kernel/time/Kconfig"
+config HAVE_SMP
+ bool
+ help
+ This option should be selected by machines which have an SMP-
+ capable CPU.
+
+ The only effect of this option is to make the SMP-related
+ options available to the user for configuration.
+
config SMP
bool "Symmetric Multi-Processing"
depends on CPU_V6K || CPU_V7
depends on GENERIC_CLOCKEVENTS
- depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
- MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
- ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
- ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_HIGHBANK || SOC_IMX6Q
+ depends on HAVE_SMP
depends on MMU
select USE_GENERIC_SMP_HELPERS
select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 7f2347b..e1efbca 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -17,6 +17,7 @@ choice
config ARCH_EXYNOS4
bool "SAMSUNG EXYNOS4"
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
Samsung EXYNOS4 SoCs based systems
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 5f7f9c2..29a3d61 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -615,6 +615,7 @@ config SOC_IMX6Q
select HAVE_IMX_GPC
select HAVE_IMX_MMDC
select HAVE_IMX_SRC
+ select HAVE_SMP
select USE_OF
help
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index ebde97f..e6beaff 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -67,6 +67,7 @@ config MSM_SOC_REV_A
bool
config ARCH_MSM_SCORPIONMP
bool
+ select HAVE_SMP
config ARCH_MSM_ARM11
bool
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index c841578..bb1b670 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -43,6 +43,7 @@ config ARCH_OMAP4
depends on ARCH_OMAP2PLUS
select CPU_V7
select ARM_GIC
+ select HAVE_SMP
select LOCAL_TIMERS if SMP
select MIGHT_HAVE_CACHE_L2X0
select PL310_ERRATA_588369
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 3dd620f..c593be4 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -12,6 +12,7 @@ config REALVIEW_EB_A9MP
bool "Support Multicore Cortex-A9 Tile"
depends on MACH_REALVIEW_EB
select CPU_V7
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
Enable support for the Cortex-A9MPCore tile fitted to the
@@ -22,6 +23,7 @@ config REALVIEW_EB_ARM11MP
depends on MACH_REALVIEW_EB
select CPU_V6K
select ARCH_HAS_BARRIERS if SMP
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
help
Enable support for the ARM11MPCore tile fitted to the Realview(R)
@@ -41,6 +43,7 @@ config MACH_REALVIEW_PB11MP
select CPU_V6K
select ARM_GIC
select HAVE_PATA_PLATFORM
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select ARCH_HAS_BARRIERS if SMP
help
@@ -82,6 +85,7 @@ config MACH_REALVIEW_PBX
bool "Support RealView(R) Platform Baseboard Explore"
select ARM_GIC
select HAVE_PATA_PLATFORM
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
select ZONE_DMA if SPARSEMEM
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index a8aefc8..9b3d0fb 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -8,6 +8,7 @@ config ARCH_VEXPRESS_CA9X4
select ARM_ERRATA_720789
select ARM_ERRATA_751472
select ARM_ERRATA_753970
+ select HAVE_SMP
select MIGHT_HAVE_CACHE_L2X0
endmenu
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 1/5] ARM: l2x0/pl310: Refactor Kconfig to be more maintainable
From: Dave Martin @ 2011-12-15 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323964434-6764-1-git-send-email-dave.martin@linaro.org>
Making CACHE_L2X0 depend on (huge list of MACH_ and ARCH_ configs)
is bothersome to maintain and likely to lead to merge conflicts.
This patch moves the knowledge of which platforms have a L2x0 or
PL310 cache controller to the individual machines. To enable this,
a new MIGHT_HAVE_CACHE_L2X0 config option is introduced to allow
machines to indicate that they may have such a cache controller
independently of each other.
Boards/SoCs which cannot reliably operate without the L2 cache
controller support will need to select CACHE_L2X0 directly from
their own Kconfigs instead. This applies to some TrustZone-enabled
boards where Linux runs in the Normal World, for example.
Signed-off-by: Dave Martin <dave.martin@linaro.org>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
(for cns3xxx)
Acked-by: Tony Lindgren <tony@atomide.com>
(for omap)
---
Changes:
v5: Minor change to the Kconfig help text to make it more
informative.
arch/arm/Kconfig | 8 ++++++++
arch/arm/mach-exynos/Kconfig | 1 +
arch/arm/mach-omap2/Kconfig | 1 +
arch/arm/mach-realview/Kconfig | 5 +++++
arch/arm/mach-vexpress/Kconfig | 1 +
arch/arm/mm/Kconfig | 23 ++++++++++++++++-------
arch/arm/plat-mxc/Kconfig | 1 +
7 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 44789ef..16a4b9e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -344,6 +344,7 @@ config ARCH_HIGHBANK
select CPU_V7
select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU
+ select MIGHT_HAVE_CACHE_L2X0
select USE_OF
help
Support for the Calxeda Highbank SoC based boards.
@@ -361,6 +362,7 @@ config ARCH_CNS3XXX
select CPU_V6K
select GENERIC_CLOCKEVENTS
select ARM_GIC
+ select MIGHT_HAVE_CACHE_L2X0
select MIGHT_HAVE_PCI
select PCI_DOMAINS if PCI
help
@@ -381,6 +383,7 @@ config ARCH_PRIMA2
select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP
select GENERIC_IRQ_CHIP
+ select MIGHT_HAVE_CACHE_L2X0
select USE_OF
select ZONE_DMA
help
@@ -633,6 +636,7 @@ config ARCH_TEGRA
select GENERIC_GPIO
select HAVE_CLK
select HAVE_SCHED_CLOCK
+ select MIGHT_HAVE_CACHE_L2X0
select ARCH_HAS_CPUFREQ
help
This enables support for NVIDIA Tegra based systems (Tegra APX,
@@ -703,6 +707,7 @@ config ARCH_SHMOBILE
select CLKDEV_LOOKUP
select HAVE_MACH_CLKDEV
select GENERIC_CLOCKEVENTS
+ select MIGHT_HAVE_CACHE_L2X0
select NO_IOPORT
select SPARSE_IRQ
select MULTI_IRQ_HANDLER
@@ -904,6 +909,7 @@ config ARCH_U8500
select CLKDEV_LOOKUP
select ARCH_REQUIRE_GPIOLIB
select ARCH_HAS_CPUFREQ
+ select MIGHT_HAVE_CACHE_L2X0
help
Support for ST-Ericsson's Ux500 architecture
@@ -914,6 +920,7 @@ config ARCH_NOMADIK
select CPU_ARM926T
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
+ select MIGHT_HAVE_CACHE_L2X0
select ARCH_REQUIRE_GPIOLIB
help
Support for the Nomadik platform by ST-Ericsson
@@ -973,6 +980,7 @@ config ARCH_ZYNQ
select ARM_GIC
select ARM_AMBA
select ICST
+ select MIGHT_HAVE_CACHE_L2X0
select USE_OF
help
Support for Xilinx Zynq ARM Cortex A9 Platform
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 724ec0f..7f2347b 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -17,6 +17,7 @@ choice
config ARCH_EXYNOS4
bool "SAMSUNG EXYNOS4"
+ select MIGHT_HAVE_CACHE_L2X0
help
Samsung EXYNOS4 SoCs based systems
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 5034147..c841578 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -44,6 +44,7 @@ config ARCH_OMAP4
select CPU_V7
select ARM_GIC
select LOCAL_TIMERS if SMP
+ select MIGHT_HAVE_CACHE_L2X0
select PL310_ERRATA_588369
select PL310_ERRATA_727915
select ARM_ERRATA_720789
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index dba6d0c..3dd620f 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -12,6 +12,7 @@ config REALVIEW_EB_A9MP
bool "Support Multicore Cortex-A9 Tile"
depends on MACH_REALVIEW_EB
select CPU_V7
+ select MIGHT_HAVE_CACHE_L2X0
help
Enable support for the Cortex-A9MPCore tile fitted to the
Realview(R) Emulation Baseboard platform.
@@ -21,6 +22,7 @@ config REALVIEW_EB_ARM11MP
depends on MACH_REALVIEW_EB
select CPU_V6K
select ARCH_HAS_BARRIERS if SMP
+ select MIGHT_HAVE_CACHE_L2X0
help
Enable support for the ARM11MPCore tile fitted to the Realview(R)
Emulation Baseboard platform.
@@ -39,6 +41,7 @@ config MACH_REALVIEW_PB11MP
select CPU_V6K
select ARM_GIC
select HAVE_PATA_PLATFORM
+ select MIGHT_HAVE_CACHE_L2X0
select ARCH_HAS_BARRIERS if SMP
help
Include support for the ARM(R) RealView(R) Platform Baseboard for
@@ -51,6 +54,7 @@ config MACH_REALVIEW_PB1176
select CPU_V6
select ARM_GIC
select HAVE_TCM
+ select MIGHT_HAVE_CACHE_L2X0
help
Include support for the ARM(R) RealView(R) Platform Baseboard for
ARM1176JZF-S.
@@ -78,6 +82,7 @@ config MACH_REALVIEW_PBX
bool "Support RealView(R) Platform Baseboard Explore"
select ARM_GIC
select HAVE_PATA_PLATFORM
+ select MIGHT_HAVE_CACHE_L2X0
select ARCH_SPARSEMEM_ENABLE if CPU_V7 && !REALVIEW_HIGH_PHYS_OFFSET
select ZONE_DMA if SPARSEMEM
help
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 9311484..a8aefc8 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -8,5 +8,6 @@ config ARCH_VEXPRESS_CA9X4
select ARM_ERRATA_720789
select ARM_ERRATA_751472
select ARM_ERRATA_753970
+ select MIGHT_HAVE_CACHE_L2X0
endmenu
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 67f75a0..acb1c36 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -816,14 +816,23 @@ config CACHE_FEROCEON_L2_WRITETHROUGH
Say Y here to use the Feroceon L2 cache in writethrough mode.
Unless you specifically require this, say N for writeback mode.
+config MIGHT_HAVE_CACHE_L2X0
+ bool
+ help
+ This option should be selected by machines which have a L2x0
+ or PL310 cache controller, but where its use is optional.
+
+ The only effect of this option is to make CACHE_L2X0 and
+ related options available to the user for configuration.
+
+ Boards or SoCs which always require the cache controller
+ support to be present should select CACHE_L2X0 directly
+ instead of this option, thus preventing the user from
+ inadvertently configuring a broken kernel.
+
config CACHE_L2X0
- bool "Enable the L2x0 outer cache controller"
- depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
- REALVIEW_EB_A9MP || ARCH_IMX_V6_V7 || MACH_REALVIEW_PBX || \
- ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
- ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \
- ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_HIGHBANK
- default y
+ bool "Enable the L2x0 outer cache controller" if MIGHT_HAVE_CACHE_L2X0
+ default MIGHT_HAVE_CACHE_L2X0
select OUTER_CACHE
select OUTER_CACHE_SYNC
help
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index b3a1f2b..b30708e 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -20,6 +20,7 @@ config ARCH_IMX_V6_V7
bool "i.MX3, i.MX6"
select AUTO_ZRELADDR if !ZBOOT_ROM
select ARM_PATCH_PHYS_VIRT
+ select MIGHT_HAVE_CACHE_L2X0
help
This enables support for systems based on the Freescale i.MX3 and i.MX6
family.
--
1.7.4.1
^ permalink raw reply related
* [PATCH v5 0/5] Refactor common Kconfigs for easier maintenance
From: Dave Martin @ 2011-12-15 15:53 UTC (permalink / raw)
To: linux-arm-kernel
Common Kconfig options which depend on a long list of board- and
SoC- specific Kconfigs can be cumbersome to maintain, leading to
annoying merge conflicts (although rather trivial ones).
This series factors out the dependencies of CACHE_L2X0 and SMP so
that the knowledge about when these can be enabled is moved to the
relevant board/SoC Kconfig files instead. New
MIGHT_HAVE_CACHE_L2X0 and HAVE_SMP options are defined to mediate
the dependencies.
This series has been substantially reworked compared with the
previous post, and is now in two parts:
* The first two patches simply refactor the way the Kconfig
options for CACHE_L2X0 and SMP are implemented, without
making any other changes.
* The final three patches apply functional changes suggested by
the contributors to this series, to make the config
dependencies more correct for some specific boards.
Thanks to Rob Herring, Shawn Guo and Russell King for their
contributions to this series. Thanks also to David Brown for
pointing out the lack of a comprehensive CC list.
I have briefly build-tested on some of the affected boards, but any
further reviews or Tested-Bys would be much appreciated.
Dave Martin (5):
ARM: l2x0/pl310: Refactor Kconfig to be more maintainable
ARM: SMP: Refactor Kconfig to be more maintainable
omap4: Unconditionally require l2x0 L2 cache controller support
highbank: Unconditionally require l2x0 L2 cache controller support
imx6q: Remove unconditional dependency on l2x0 L2 cache support
arch/arm/Kconfig | 26 ++++++++++++++++++++++----
arch/arm/mach-exynos/Kconfig | 2 ++
arch/arm/mach-imx/Kconfig | 2 +-
arch/arm/mach-msm/Kconfig | 1 +
arch/arm/mach-omap2/Kconfig | 2 ++
arch/arm/mach-realview/Kconfig | 9 +++++++++
arch/arm/mach-vexpress/Kconfig | 2 ++
arch/arm/mm/Kconfig | 23 ++++++++++++++++-------
arch/arm/plat-mxc/Kconfig | 1 +
9 files changed, 56 insertions(+), 12 deletions(-)
--
1.7.4.1
^ permalink raw reply
* Re: [PATCH v4 REPOST 5/5] imx6q: Remove unconditional dependency on
From: Dave Martin @ 2011-12-15 15:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111215015414.GQ28768@b20223-02.ap.freescale.net>
On Thu, Dec 15, 2011 at 09:54:15AM +0800, Richard Zhao wrote:
> On Thu, Dec 15, 2011 at 09:46:20AM +0800, Shawn Guo wrote:
> > On Thu, Dec 15, 2011 at 09:02:20AM +0800, Richard Zhao wrote:
> > > On Wed, Dec 14, 2011 at 03:01:19PM +0000, Dave Martin wrote:
> > > > On Wed, Dec 14, 2011 at 10:05:04PM +0800, Richard Zhao wrote:
> > > > > On Wed, Dec 14, 2011 at 09:26:24PM +0800, Shawn Guo wrote:
> > > > > > Hi Dave,
> > > > > >
> > > > > > Sorry for that I did not look into previous post to point it out.
> > > > > >
> > > > > > On Wed, Dec 14, 2011 at 11:39:41AM +0000, Dave Martin wrote:
> > > > > > > The i.MX6 Quad SoC will work without the l2x0 L2 cache controller
> > > > > > > support built into the kernel, so this patch removes the dependency
> > > > > > > on CACHE_L2X0 and selects MIGHT_HAVE_CACHE_L2X0 instead.
> > > > > > >
> > > > > > > This makes the l2x0 support optional, so that it can be turned off
> > > > > > > when desired for debugging purposes etc.
> > > > > > >
> > > > > > > Thanks to Shawn Guo for this suggestion. [1]
> > > > > > >
> > > > > > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > > > > > >
> > > > > > > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074602.html
> > > > > > > ---
> > > > > > > arch/arm/mach-imx/Kconfig | 2 +-
> > > > > > > 1 files changed, 1 insertions(+), 1 deletions(-)
> > > > > > >
> > > > > > > diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> > > > > > > index 29a3d61..1fb93f2 100644
> > > > > > > --- a/arch/arm/mach-imx/Kconfig
> > > > > > > +++ b/arch/arm/mach-imx/Kconfig
> > > > > > > @@ -609,13 +609,13 @@ comment "i.MX6 family:"
> > > > > > > config SOC_IMX6Q
> > > > > > > bool "i.MX6 Quad support"
> > > > > > > select ARM_GIC
> > > > > > > - select CACHE_L2X0
> > > > > > > select CPU_V7
> > > > > > > select HAVE_ARM_SCU
> > > > > > > select HAVE_IMX_GPC
> > > > > > > select HAVE_IMX_MMDC
> > > > > > > select HAVE_IMX_SRC
> > > > > > > select HAVE_SMP
> > > > > > > + select MIGHT_HAVE_CACHE_L2X0
> > > > > >
> > > > > > The option SOC_IMX6Q is only available when ARCH_IMX_V6_V7 is selected.
> > > > > > Since MIGHT_HAVE_CACHE_L2X0 has been selected by ARCH_IMX_V6_V7 in
> > > > > > patch #1, this line seems redundant here.
> > > > > Would it be better keep this one and remove patch #1 one? imx5 doesn't have
> > > > > l2x0.
> > > >
> > > > Do you mean to remove MIGHT_HAVE_CACHE_L2X0 from ARCH_IMX_V6_V7, and select
> > > > it only from SOC_IMX6Q?
> > > Yes, I think it's more precise. Shawn?
> > >
> > No.
> >
> > * imx5 hardware does have L2, and it's just not set up in the kernel
> > (I do not know why).
> > * Currently, ARCH_IMX_V6_V7 only covers imx3 and imx6, and both are
> > calling l2x0 init function to set L2 up.
> > * When we merge mach-mx5 into mach-imx to have ARCH_IMX_V6_V7 cover
> > imx3, imx5 and imx6, there is no reason for us to not set L2 up for
> > imx5 too.
> >
> > So MIGHT_HAVE_CACHE_L2X0 really should be selected by ARCH_IMX_V6_V7.
> mx5/cortex-a8 don't use L2X0. But that's ok. MIGHT_HAVE_CACHE_L2X0 is just a hint.
> Please Shawn's suggestion.
OK, my local series has what I believe to be the correct change;
I will repost based on that.
Cheers
---Dave
^ permalink raw reply
* Re: [PATCH 12/57] arm: mach-shmobile: Add LCDC tx_dev field to
From: Guennadi Liakhovetski @ 2011-12-15 14:01 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-13-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent
On Tue, 13 Dec 2011, Laurent Pinchart wrote:
> Make sure the transmitter devices get registered before the associated
> LCDC devices.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
> arch/arm/mach-shmobile/board-ap4evb.c | 272 ++++++++++++++++---------------
> arch/arm/mach-shmobile/board-mackerel.c | 66 ++++----
> 2 files changed, 176 insertions(+), 162 deletions(-)
>
> diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
> index dca4860..e0a6b3d 100644
> --- a/arch/arm/mach-shmobile/board-ap4evb.c
> +++ b/arch/arm/mach-shmobile/board-ap4evb.c
> @@ -445,82 +445,6 @@ static struct platform_device usb1_host_device = {
> .resource = usb1_host_resources,
> };
>
> -static const struct fb_videomode ap4evb_lcdc_modes[] = {
> - {
> -#ifdef CONFIG_AP4EVB_QHD
> - .name = "R63302(QHD)",
> - .xres = 544,
> - .yres = 961,
> - .left_margin = 72,
> - .right_margin = 600,
> - .hsync_len = 16,
> - .upper_margin = 8,
> - .lower_margin = 8,
> - .vsync_len = 2,
> - .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
> -#else
> - .name = "WVGA Panel",
> - .xres = 800,
> - .yres = 480,
> - .left_margin = 220,
> - .right_margin = 110,
> - .hsync_len = 70,
> - .upper_margin = 20,
> - .lower_margin = 5,
> - .vsync_len = 5,
> - .sync = 0,
> -#endif
> - },
> -};
> -static struct sh_mobile_meram_cfg lcd_meram_cfg = {
> - .icb[0] = {
> - .marker_icb = 28,
> - .cache_icb = 24,
> - .meram_offset = 0x0,
> - .meram_size = 0x40,
> - },
> - .icb[1] = {
> - .marker_icb = 29,
> - .cache_icb = 25,
> - .meram_offset = 0x40,
> - .meram_size = 0x40,
> - },
> -};
> -
> -static struct sh_mobile_lcdc_info lcdc_info = {
> - .meram_dev = &meram_info,
> - .ch[0] = {
> - .chan = LCDC_CHAN_MAINLCD,
> - .fourcc = V4L2_PIX_FMT_RGB565,
> - .lcd_cfg = ap4evb_lcdc_modes,
> - .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
> - .meram_cfg = &lcd_meram_cfg,
> - }
> -};
> -
> -static struct resource lcdc_resources[] = {
> - [0] = {
> - .name = "LCDC",
> - .start = 0xfe940000, /* P4-only space */
> - .end = 0xfe943fff,
> - .flags = IORESOURCE_MEM,
> - },
> - [1] = {
> - .start = intcs_evt2irq(0x580),
> - .flags = IORESOURCE_IRQ,
> - },
> -};
> -
> -static struct platform_device lcdc_device = {
> - .name = "sh_mobile_lcdc_fb",
> - .num_resources = ARRAY_SIZE(lcdc_resources),
> - .resource = lcdc_resources,
> - .dev = {
> - .platform_data = &lcdc_info,
> - .coherent_dma_mask = ~0,
> - },
> -};
> -
> /*
> * QHD display
> */
> @@ -601,6 +525,8 @@ static struct resource mipidsi0_resources[] = {
> },
> };
>
> +static struct sh_mobile_lcdc_info lcdc_info;
> +
> static struct sh_mipi_dsi_info mipidsi0_info = {
> .data_format = MIPI_RGB888,
> .lcd_chan = &lcdc_info.ch[0],
> @@ -627,6 +553,86 @@ static struct platform_device *qhd_devices[] __initdata = {
> };
> #endif /* CONFIG_AP4EVB_QHD */
>
> +/* LCDC0 */
> +static const struct fb_videomode ap4evb_lcdc_modes[] = {
Hm, I must be missing something. I thought you were moving all the structs
around to make them available for reference _without_ forward
declarations. But you _do_ end up using a forward declaration anyway. Here
and for HDMI below too. So, what's the point? Why not just forward declare
that one struct, that's needed and leave the rest where it currently is
in the file?
> + {
> +#ifdef CONFIG_AP4EVB_QHD
> + .name = "R63302(QHD)",
> + .xres = 544,
> + .yres = 961,
> + .left_margin = 72,
> + .right_margin = 600,
> + .hsync_len = 16,
> + .upper_margin = 8,
> + .lower_margin = 8,
> + .vsync_len = 2,
> + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
> +#else
> + .name = "WVGA Panel",
> + .xres = 800,
> + .yres = 480,
> + .left_margin = 220,
> + .right_margin = 110,
> + .hsync_len = 70,
> + .upper_margin = 20,
> + .lower_margin = 5,
> + .vsync_len = 5,
> + .sync = 0,
> +#endif
> + },
> +};
> +static struct sh_mobile_meram_cfg lcd_meram_cfg = {
> + .icb[0] = {
> + .marker_icb = 28,
> + .cache_icb = 24,
> + .meram_offset = 0x0,
> + .meram_size = 0x40,
> + },
> + .icb[1] = {
> + .marker_icb = 29,
> + .cache_icb = 25,
> + .meram_offset = 0x40,
> + .meram_size = 0x40,
> + },
> +};
> +
> +static struct sh_mobile_lcdc_info lcdc_info = {
> + .meram_dev = &meram_info,
> + .ch[0] = {
> + .chan = LCDC_CHAN_MAINLCD,
> + .fourcc = V4L2_PIX_FMT_RGB565,
> + .lcd_cfg = ap4evb_lcdc_modes,
> + .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
> + .meram_cfg = &lcd_meram_cfg,
> +#ifdef CONFIG_AP4EVB_QHD
> + .tx_dev = &mipidsi0_device,
> +#endif
> + }
> +};
> +
> +static struct resource lcdc_resources[] = {
> + [0] = {
> + .name = "LCDC",
> + .start = 0xfe940000, /* P4-only space */
> + .end = 0xfe943fff,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + .start = intcs_evt2irq(0x580),
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device lcdc_device = {
> + .name = "sh_mobile_lcdc_fb",
> + .num_resources = ARRAY_SIZE(lcdc_resources),
> + .resource = lcdc_resources,
> + .dev = {
> + .platform_data = &lcdc_info,
> + .coherent_dma_mask = ~0,
> + },
> +};
> +
> /* FSI */
> #define IRQ_FSI evt2irq(0x1840)
> static int __fsi_set_rate(struct clk *clk, long rate, int enable)
> @@ -793,6 +799,62 @@ static struct platform_device fsi_device = {
> static struct platform_device fsi_ak4643_device = {
> .name = "sh_fsi2_a_ak4643",
> };
> +
> +/* LCDC1 */
> +static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
> + unsigned long *parent_freq);
> +
> +static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info;
> +
> +static struct sh_mobile_hdmi_info hdmi_info = {
> + .lcd_chan = &sh_mobile_lcdc1_info.ch[0],
> + .flags = HDMI_SND_SRC_SPDIF,
> + .clk_optimize_parent = ap4evb_clk_optimize,
> +};
> +
> +static struct resource hdmi_resources[] = {
> + [0] = {
> + .name = "HDMI",
> + .start = 0xe6be0000,
> + .end = 0xe6be00ff,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + /* There's also an HDMI interrupt on INTCS @ 0x18e0 */
> + .start = evt2irq(0x17e0),
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device hdmi_device = {
> + .name = "sh-mobile-hdmi",
> + .num_resources = ARRAY_SIZE(hdmi_resources),
> + .resource = hdmi_resources,
> + .id = -1,
> + .dev = {
> + .platform_data = &hdmi_info,
> + },
> +};
> +
> +static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
> + unsigned long *parent_freq)
> +{
> + struct clk *hdmi_ick = clk_get(&hdmi_device.dev, "ick");
> + long error;
> +
> + if (IS_ERR(hdmi_ick)) {
> + int ret = PTR_ERR(hdmi_ick);
> + pr_err("Cannot get HDMI ICK: %d\n", ret);
> + return ret;
> + }
> +
> + error = clk_round_parent(hdmi_ick, target, best_freq, parent_freq, 1, 64);
> +
> + clk_put(hdmi_ick);
> +
> + return error;
> +}
> +
> static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
> .icb[0] = {
> .marker_icb = 30,
> @@ -818,6 +880,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
> .clock_divider = 1,
> .flags = LCDC_FLAGS_DWPOL,
> .meram_cfg = &hdmi_meram_cfg,
> + .tx_dev = &hdmi_device,
> }
> };
>
> @@ -845,63 +908,10 @@ static struct platform_device lcdc1_device = {
> },
> };
>
> -static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
> - unsigned long *parent_freq);
> -
> -
> -static struct sh_mobile_hdmi_info hdmi_info = {
> - .lcd_chan = &sh_mobile_lcdc1_info.ch[0],
> - .flags = HDMI_SND_SRC_SPDIF,
> - .clk_optimize_parent = ap4evb_clk_optimize,
> -};
> -
> -static struct resource hdmi_resources[] = {
> - [0] = {
> - .name = "HDMI",
> - .start = 0xe6be0000,
> - .end = 0xe6be00ff,
> - .flags = IORESOURCE_MEM,
> - },
> - [1] = {
> - /* There's also an HDMI interrupt on INTCS @ 0x18e0 */
> - .start = evt2irq(0x17e0),
> - .flags = IORESOURCE_IRQ,
> - },
> -};
> -
> -static struct platform_device hdmi_device = {
> - .name = "sh-mobile-hdmi",
> - .num_resources = ARRAY_SIZE(hdmi_resources),
> - .resource = hdmi_resources,
> - .id = -1,
> - .dev = {
> - .platform_data = &hdmi_info,
> - },
> -};
> -
> static struct platform_device fsi_hdmi_device = {
> .name = "sh_fsi2_b_hdmi",
> };
>
> -static long ap4evb_clk_optimize(unsigned long target, unsigned long *best_freq,
> - unsigned long *parent_freq)
> -{
> - struct clk *hdmi_ick = clk_get(&hdmi_device.dev, "ick");
> - long error;
> -
> - if (IS_ERR(hdmi_ick)) {
> - int ret = PTR_ERR(hdmi_ick);
> - pr_err("Cannot get HDMI ICK: %d\n", ret);
> - return ret;
> - }
> -
> - error = clk_round_parent(hdmi_ick, target, best_freq, parent_freq, 1, 64);
> -
> - clk_put(hdmi_ick);
> -
> - return error;
> -}
> -
> static struct gpio_led ap4evb_leds[] = {
> {
> .name = "led4",
> @@ -1036,9 +1046,9 @@ static struct platform_device *ap4evb_devices[] __initdata = {
> &fsi_ak4643_device,
> &fsi_hdmi_device,
> &sh_mmcif_device,
> - &lcdc1_device,
> - &lcdc_device,
> &hdmi_device,
> + &lcdc_device,
> + &lcdc1_device,
> &ceu_device,
> &ap4evb_camera,
> &meram_device,
> diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
> index 4ed0138..ccdd9fc 100644
> --- a/arch/arm/mach-shmobile/board-mackerel.c
> +++ b/arch/arm/mach-shmobile/board-mackerel.c
> @@ -431,6 +431,38 @@ static struct platform_device lcdc_device = {
> },
> };
>
> +/* HDMI */
> +static struct sh_mobile_lcdc_info hdmi_lcdc_info;
> +
> +static struct sh_mobile_hdmi_info hdmi_info = {
> + .lcd_chan = &hdmi_lcdc_info.ch[0],
> + .flags = HDMI_SND_SRC_SPDIF,
> +};
> +
> +static struct resource hdmi_resources[] = {
> + [0] = {
> + .name = "HDMI",
> + .start = 0xe6be0000,
> + .end = 0xe6be00ff,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + /* There's also an HDMI interrupt on INTCS @ 0x18e0 */
> + .start = evt2irq(0x17e0),
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device hdmi_device = {
> + .name = "sh-mobile-hdmi",
> + .num_resources = ARRAY_SIZE(hdmi_resources),
> + .resource = hdmi_resources,
> + .id = -1,
> + .dev = {
> + .platform_data = &hdmi_info,
> + },
> +};
> +
> static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
> .icb[0] = {
> .marker_icb = 30,
> @@ -445,7 +477,7 @@ static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
> .meram_size = 0x100,
> },
> };
> -/* HDMI */
> +
> static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
> .meram_dev = &mackerel_meram_info,
> .clock_source = LCDC_CLK_EXTERNAL,
> @@ -456,6 +488,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
> .clock_divider = 1,
> .flags = LCDC_FLAGS_DWPOL,
> .meram_cfg = &hdmi_meram_cfg,
> + .tx_dev = &hdmi_device,
> }
> };
>
> @@ -483,35 +516,6 @@ static struct platform_device hdmi_lcdc_device = {
> },
> };
>
> -static struct sh_mobile_hdmi_info hdmi_info = {
> - .lcd_chan = &hdmi_lcdc_info.ch[0],
> - .flags = HDMI_SND_SRC_SPDIF,
> -};
> -
> -static struct resource hdmi_resources[] = {
> - [0] = {
> - .name = "HDMI",
> - .start = 0xe6be0000,
> - .end = 0xe6be00ff,
> - .flags = IORESOURCE_MEM,
> - },
> - [1] = {
> - /* There's also an HDMI interrupt on INTCS @ 0x18e0 */
> - .start = evt2irq(0x17e0),
> - .flags = IORESOURCE_IRQ,
> - },
> -};
> -
> -static struct platform_device hdmi_device = {
> - .name = "sh-mobile-hdmi",
> - .num_resources = ARRAY_SIZE(hdmi_resources),
> - .resource = hdmi_resources,
> - .id = -1,
> - .dev = {
> - .platform_data = &hdmi_info,
> - },
> -};
> -
> static struct platform_device fsi_hdmi_device = {
> .name = "sh_fsi2_b_hdmi",
> };
> @@ -1313,8 +1317,8 @@ static struct platform_device *mackerel_devices[] __initdata = {
> &sh_mmcif_device,
> &ceu_device,
> &mackerel_camera,
> - &hdmi_lcdc_device,
> &hdmi_device,
> + &hdmi_lcdc_device,
> &meram_device,
> };
>
Sorry, could you elaborate, why this is needed? If this is really
important, then I'd prefer to test this before committing. If OTOH this is
unimportant, and my assumption, that normally it's the platform driver
registration order, that's important, not device registration order, is
correct, then you don't have to swap the order?
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH 48/57] fbdev: sh_mobile_meram: Allocate ICBs automatically
From: Laurent Pinchart @ 2011-12-15 11:39 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-49-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Damian,
On Thursday 15 December 2011 03:58:12 Damian Hobson-Garcia wrote:
> Hi Laurent,
>
> On 2011/12/13 23:02, Laurent Pinchart wrote:
> > Instead of manually specifying the ICBs to use in platform data,
> > allocate them automatically at runtime.
> >
> > The MERAM registration function now returns a pointer to an opaque MERAM
> > object, which is passed to the update and unregistration functions.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
>
> So one concern that I have about this is in regards to sharing ICBs with
> user-space drivers. Since there are user space drivers (via UIO) for blocks
> like the VEU, that may want to have access to MERAM, we need a way to
> communicate which ICBs are free to user space. With the hard-coded platform
> data we could easily assume that kernel drivers would use, for example, the
> upper 16 ICBs and so user-space drivers were free to use the lower 16.
You're right, I forgot about that :-/
> One simple temporary workaround might be to provide a range of useable ICBs
> in the platform data. The MERAM memory allocation range can always easily be
> tweaked by using the meram_resources structure.
That sounds good to me. I'll implement that.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 47/57] fbdev: sh_mobile_meram: Use genalloc to manage MERAM allocation
From: Laurent Pinchart @ 2011-12-15 11:37 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-48-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Damian,
Thanks for the review.
On Thursday 15 December 2011 03:43:06 Damian Hobson-Garcia wrote:
> On 2011/12/13 23:02, Laurent Pinchart wrote:
> > @@ -195,43 +196,40 @@ static int meram_check_overlap(struct
> > sh_mobile_meram_priv *priv,
> >
> > test_bit(new->cache_icb, &priv->used_icb))
> >
> > return 1;
> >
> > - for (i = 0; i < MERAM_ICB_NUM; i++) {
> > - if (!test_bit(i, &priv->used_icb))
> > - continue;
> > -
> > - used_start = MERAM_CACHE_START(priv->icbs[i].region);
> > - used_end = MERAM_CACHE_END(priv->icbs[i].region);
> > - meram_start = new->meram_offset;
> > - meram_end = new->meram_offset + new->meram_size;
> > -
> > - if ((meram_start >= used_start && meram_start < used_end) ||
> > - (meram_end > used_start && meram_end < used_end))
> > - return 1;
> > - }
> > -
> >
> > return 0;
> >
> > }
> >
> > -/* Mark the specified ICB as used. */
> > -static void meram_mark(struct sh_mobile_meram_priv *priv,
> > +/* Allocate memory for the ICBs and mark them as used. */
> > +static int meram_alloc(struct sh_mobile_meram_priv *priv,
> >
> > const struct sh_mobile_meram_icb_cfg *new,
> > int pixelformat)
> >
> > {
> >
> > + struct sh_mobile_meram_icb *marker = &priv->icbs[new->marker_icb];
> > + unsigned long mem;
> > +
> > + mem = gen_pool_alloc(priv->pool, new->meram_size * 1024);
> > + if (mem = 0)
> > + return -ENOMEM;
> > +
> >
> > __set_bit(new->marker_icb, &priv->used_icb);
> > __set_bit(new->cache_icb, &priv->used_icb);
> >
> > - priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,
> > - new->meram_size);
> > - priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
> > - new->meram_size);
> > - priv->icbs[new->marker_icb].current_reg = 1;
> > - priv->icbs[new->marker_icb].pixelformat = pixelformat;
> > + marker->offset = mem - priv->meram;
>
> I might have missed this somewhere, but it doesn't look like priv->meram
> is assigned anywhere.
Oops. That got lost in a rebase operation :-/ I'll fix it.
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH 48/57] fbdev: sh_mobile_meram: Allocate ICBs automatically
From: Damian Hobson-Garcia @ 2011-12-15 2:58 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-49-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent,
On 2011/12/13 23:02, Laurent Pinchart wrote:
> Instead of manually specifying the ICBs to use in platform data,
> allocate them automatically at runtime.
>
> The MERAM registration function now returns a pointer to an opaque MERAM
> object, which is passed to the update and unregistration functions.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
So one concern that I have about this is in regards to sharing ICBs with
user-space drivers. Since there are user space drivers (via UIO) for
blocks like the VEU, that may want to have access to MERAM, we need
a way to communicate which ICBs are free to user space. With the
hard-coded platform data we could easily assume that kernel drivers
would use, for example, the upper 16 ICBs and so user-space drivers were
free to use the lower 16.
One simple temporary workaround might be to provide a range of useable
ICBs in the platform data. The MERAM memory allocation range can always
easily be tweaked by using the meram_resources structure.
Thanks,
Damian
^ permalink raw reply
* Re: [PATCH 47/57] fbdev: sh_mobile_meram: Use genalloc to manage
From: Damian Hobson-Garcia @ 2011-12-15 2:43 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323784972-24205-48-git-send-email-laurent.pinchart@ideasonboard.com>
On 2011/12/13 23:02, Laurent Pinchart wrote:
> @@ -195,43 +196,40 @@ static int meram_check_overlap(struct sh_mobile_meram_priv *priv,
> test_bit(new->cache_icb, &priv->used_icb))
> return 1;
>
> - for (i = 0; i < MERAM_ICB_NUM; i++) {
> - if (!test_bit(i, &priv->used_icb))
> - continue;
> -
> - used_start = MERAM_CACHE_START(priv->icbs[i].region);
> - used_end = MERAM_CACHE_END(priv->icbs[i].region);
> - meram_start = new->meram_offset;
> - meram_end = new->meram_offset + new->meram_size;
> -
> - if ((meram_start >= used_start && meram_start < used_end) ||
> - (meram_end > used_start && meram_end < used_end))
> - return 1;
> - }
> -
> return 0;
> }
>
> -/* Mark the specified ICB as used. */
> -static void meram_mark(struct sh_mobile_meram_priv *priv,
> +/* Allocate memory for the ICBs and mark them as used. */
> +static int meram_alloc(struct sh_mobile_meram_priv *priv,
> const struct sh_mobile_meram_icb_cfg *new,
> int pixelformat)
> {
> + struct sh_mobile_meram_icb *marker = &priv->icbs[new->marker_icb];
> + unsigned long mem;
> +
> + mem = gen_pool_alloc(priv->pool, new->meram_size * 1024);
> + if (mem = 0)
> + return -ENOMEM;
> +
> __set_bit(new->marker_icb, &priv->used_icb);
> __set_bit(new->cache_icb, &priv->used_icb);
>
> - priv->icbs[new->marker_icb].region = MERAM_CACHE_SET(new->meram_offset,
> - new->meram_size);
> - priv->icbs[new->cache_icb].region = MERAM_CACHE_SET(new->meram_offset,
> - new->meram_size);
> - priv->icbs[new->marker_icb].current_reg = 1;
> - priv->icbs[new->marker_icb].pixelformat = pixelformat;
> + marker->offset = mem - priv->meram;
I might have missed this somewhere, but it doesn't look like priv->meram
is assigned anywhere.
Damian
--
Damian Hobson-Garcia
IGEL Co.,Ltd
http://www.igel.co.jp
^ permalink raw reply
* Re: [PATCH v4 REPOST 5/5] imx6q: Remove unconditional dependency on
From: Richard Zhao @ 2011-12-15 1:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111215014619.GB3259@S2101-09.ap.freescale.net>
On Thu, Dec 15, 2011 at 09:46:20AM +0800, Shawn Guo wrote:
> On Thu, Dec 15, 2011 at 09:02:20AM +0800, Richard Zhao wrote:
> > On Wed, Dec 14, 2011 at 03:01:19PM +0000, Dave Martin wrote:
> > > On Wed, Dec 14, 2011 at 10:05:04PM +0800, Richard Zhao wrote:
> > > > On Wed, Dec 14, 2011 at 09:26:24PM +0800, Shawn Guo wrote:
> > > > > Hi Dave,
> > > > >
> > > > > Sorry for that I did not look into previous post to point it out.
> > > > >
> > > > > On Wed, Dec 14, 2011 at 11:39:41AM +0000, Dave Martin wrote:
> > > > > > The i.MX6 Quad SoC will work without the l2x0 L2 cache controller
> > > > > > support built into the kernel, so this patch removes the dependency
> > > > > > on CACHE_L2X0 and selects MIGHT_HAVE_CACHE_L2X0 instead.
> > > > > >
> > > > > > This makes the l2x0 support optional, so that it can be turned off
> > > > > > when desired for debugging purposes etc.
> > > > > >
> > > > > > Thanks to Shawn Guo for this suggestion. [1]
> > > > > >
> > > > > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > > > > >
> > > > > > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074602.html
> > > > > > ---
> > > > > > arch/arm/mach-imx/Kconfig | 2 +-
> > > > > > 1 files changed, 1 insertions(+), 1 deletions(-)
> > > > > >
> > > > > > diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> > > > > > index 29a3d61..1fb93f2 100644
> > > > > > --- a/arch/arm/mach-imx/Kconfig
> > > > > > +++ b/arch/arm/mach-imx/Kconfig
> > > > > > @@ -609,13 +609,13 @@ comment "i.MX6 family:"
> > > > > > config SOC_IMX6Q
> > > > > > bool "i.MX6 Quad support"
> > > > > > select ARM_GIC
> > > > > > - select CACHE_L2X0
> > > > > > select CPU_V7
> > > > > > select HAVE_ARM_SCU
> > > > > > select HAVE_IMX_GPC
> > > > > > select HAVE_IMX_MMDC
> > > > > > select HAVE_IMX_SRC
> > > > > > select HAVE_SMP
> > > > > > + select MIGHT_HAVE_CACHE_L2X0
> > > > >
> > > > > The option SOC_IMX6Q is only available when ARCH_IMX_V6_V7 is selected.
> > > > > Since MIGHT_HAVE_CACHE_L2X0 has been selected by ARCH_IMX_V6_V7 in
> > > > > patch #1, this line seems redundant here.
> > > > Would it be better keep this one and remove patch #1 one? imx5 doesn't have
> > > > l2x0.
> > >
> > > Do you mean to remove MIGHT_HAVE_CACHE_L2X0 from ARCH_IMX_V6_V7, and select
> > > it only from SOC_IMX6Q?
> > Yes, I think it's more precise. Shawn?
> >
> No.
>
> * imx5 hardware does have L2, and it's just not set up in the kernel
> (I do not know why).
> * Currently, ARCH_IMX_V6_V7 only covers imx3 and imx6, and both are
> calling l2x0 init function to set L2 up.
> * When we merge mach-mx5 into mach-imx to have ARCH_IMX_V6_V7 cover
> imx3, imx5 and imx6, there is no reason for us to not set L2 up for
> imx5 too.
>
> So MIGHT_HAVE_CACHE_L2X0 really should be selected by ARCH_IMX_V6_V7.
mx5/cortex-a8 don't use L2X0. But that's ok. MIGHT_HAVE_CACHE_L2X0 is just a hint.
Please Shawn's suggestion.
Thanks
Richard
>
> --
> Regards,
> Shawn
^ permalink raw reply
* Re: [PATCH v4 REPOST 5/5] imx6q: Remove unconditional dependency on
From: Shawn Guo @ 2011-12-15 1:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111215010219.GP28768@b20223-02.ap.freescale.net>
On Thu, Dec 15, 2011 at 09:02:20AM +0800, Richard Zhao wrote:
> On Wed, Dec 14, 2011 at 03:01:19PM +0000, Dave Martin wrote:
> > On Wed, Dec 14, 2011 at 10:05:04PM +0800, Richard Zhao wrote:
> > > On Wed, Dec 14, 2011 at 09:26:24PM +0800, Shawn Guo wrote:
> > > > Hi Dave,
> > > >
> > > > Sorry for that I did not look into previous post to point it out.
> > > >
> > > > On Wed, Dec 14, 2011 at 11:39:41AM +0000, Dave Martin wrote:
> > > > > The i.MX6 Quad SoC will work without the l2x0 L2 cache controller
> > > > > support built into the kernel, so this patch removes the dependency
> > > > > on CACHE_L2X0 and selects MIGHT_HAVE_CACHE_L2X0 instead.
> > > > >
> > > > > This makes the l2x0 support optional, so that it can be turned off
> > > > > when desired for debugging purposes etc.
> > > > >
> > > > > Thanks to Shawn Guo for this suggestion. [1]
> > > > >
> > > > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > > > >
> > > > > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074602.html
> > > > > ---
> > > > > arch/arm/mach-imx/Kconfig | 2 +-
> > > > > 1 files changed, 1 insertions(+), 1 deletions(-)
> > > > >
> > > > > diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> > > > > index 29a3d61..1fb93f2 100644
> > > > > --- a/arch/arm/mach-imx/Kconfig
> > > > > +++ b/arch/arm/mach-imx/Kconfig
> > > > > @@ -609,13 +609,13 @@ comment "i.MX6 family:"
> > > > > config SOC_IMX6Q
> > > > > bool "i.MX6 Quad support"
> > > > > select ARM_GIC
> > > > > - select CACHE_L2X0
> > > > > select CPU_V7
> > > > > select HAVE_ARM_SCU
> > > > > select HAVE_IMX_GPC
> > > > > select HAVE_IMX_MMDC
> > > > > select HAVE_IMX_SRC
> > > > > select HAVE_SMP
> > > > > + select MIGHT_HAVE_CACHE_L2X0
> > > >
> > > > The option SOC_IMX6Q is only available when ARCH_IMX_V6_V7 is selected.
> > > > Since MIGHT_HAVE_CACHE_L2X0 has been selected by ARCH_IMX_V6_V7 in
> > > > patch #1, this line seems redundant here.
> > > Would it be better keep this one and remove patch #1 one? imx5 doesn't have
> > > l2x0.
> >
> > Do you mean to remove MIGHT_HAVE_CACHE_L2X0 from ARCH_IMX_V6_V7, and select
> > it only from SOC_IMX6Q?
> Yes, I think it's more precise. Shawn?
>
No.
* imx5 hardware does have L2, and it's just not set up in the kernel
(I do not know why).
* Currently, ARCH_IMX_V6_V7 only covers imx3 and imx6, and both are
calling l2x0 init function to set L2 up.
* When we merge mach-mx5 into mach-imx to have ARCH_IMX_V6_V7 cover
imx3, imx5 and imx6, there is no reason for us to not set L2 up for
imx5 too.
So MIGHT_HAVE_CACHE_L2X0 really should be selected by ARCH_IMX_V6_V7.
--
Regards,
Shawn
^ permalink raw reply
* Re: [PATCH v4 REPOST 5/5] imx6q: Remove unconditional dependency on
From: Richard Zhao @ 2011-12-15 1:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111214150119.GD2568@linaro.org>
On Wed, Dec 14, 2011 at 03:01:19PM +0000, Dave Martin wrote:
> On Wed, Dec 14, 2011 at 10:05:04PM +0800, Richard Zhao wrote:
> > On Wed, Dec 14, 2011 at 09:26:24PM +0800, Shawn Guo wrote:
> > > Hi Dave,
> > >
> > > Sorry for that I did not look into previous post to point it out.
> > >
> > > On Wed, Dec 14, 2011 at 11:39:41AM +0000, Dave Martin wrote:
> > > > The i.MX6 Quad SoC will work without the l2x0 L2 cache controller
> > > > support built into the kernel, so this patch removes the dependency
> > > > on CACHE_L2X0 and selects MIGHT_HAVE_CACHE_L2X0 instead.
> > > >
> > > > This makes the l2x0 support optional, so that it can be turned off
> > > > when desired for debugging purposes etc.
> > > >
> > > > Thanks to Shawn Guo for this suggestion. [1]
> > > >
> > > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > > >
> > > > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074602.html
> > > > ---
> > > > arch/arm/mach-imx/Kconfig | 2 +-
> > > > 1 files changed, 1 insertions(+), 1 deletions(-)
> > > >
> > > > diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> > > > index 29a3d61..1fb93f2 100644
> > > > --- a/arch/arm/mach-imx/Kconfig
> > > > +++ b/arch/arm/mach-imx/Kconfig
> > > > @@ -609,13 +609,13 @@ comment "i.MX6 family:"
> > > > config SOC_IMX6Q
> > > > bool "i.MX6 Quad support"
> > > > select ARM_GIC
> > > > - select CACHE_L2X0
> > > > select CPU_V7
> > > > select HAVE_ARM_SCU
> > > > select HAVE_IMX_GPC
> > > > select HAVE_IMX_MMDC
> > > > select HAVE_IMX_SRC
> > > > select HAVE_SMP
> > > > + select MIGHT_HAVE_CACHE_L2X0
> > >
> > > The option SOC_IMX6Q is only available when ARCH_IMX_V6_V7 is selected.
> > > Since MIGHT_HAVE_CACHE_L2X0 has been selected by ARCH_IMX_V6_V7 in
> > > patch #1, this line seems redundant here.
> > Would it be better keep this one and remove patch #1 one? imx5 doesn't have
> > l2x0.
>
> Do you mean to remove MIGHT_HAVE_CACHE_L2X0 from ARCH_IMX_V6_V7, and select
> it only from SOC_IMX6Q?
Yes, I think it's more precise. Shawn?
Thansk
Richard
>
> Cheers
> ---Dave
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* Re: [PATCH v4 REPOST 3/5] omap4: Unconditionally require l2x0 L2
From: Tony Lindgren @ 2011-12-14 21:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4EE90EB5.9070502@gmail.com>
* Rob Herring <robherring2@gmail.com> [111214 12:30]:
>
> On 12/14/2011 12:39 PM, Tony Lindgren wrote:
> >
> > I think we should keep L2 configurable for omaps until we have some
> > way of getting the configuration dynamically or from device tree.
> >
>
> This already exists with l2x0_of_init. OMAP just needs to start using
> it. It will initialize the l2 if present in the DT and skip it if not
> present.
That's great, that will allow doing the right thing with setting
up how to enable and disable it :) Considering that, this patch
should be OK to apply:
Acked-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply
* Re: [PATCH/RFC] mmc: add a device PM QoS constraint when a host is first claimed
From: Rafael J. Wysocki @ 2011-12-14 21:36 UTC (permalink / raw)
To: Ulf Hansson
Cc: Guennadi Liakhovetski, linux-mmc@vger.kernel.org,
linux-pm@vger.kernel.org, Chris Ball, linux-sh@vger.kernel.org
In-Reply-To: <4EE8849D.1010401@stericsson.com>
On Wednesday, December 14, 2011, Ulf Hansson wrote:
>
> >> You have a point. But I am not convinced. :-)
> >>
> >> Some host drivers already make use of autosuspend. I think this is most
> >> straightforward solution to this problem right now.
> >
> > The problem is not about _when_ to suspend (which autosuspend is about),
> > but _what_ _state_ to go when suspended. That's quite a different issue.
>
> I was kind of taking a more simple approach, I were considering
> runtime_suspend as _one_ state. Right now there is no host driver having
> different levels of runtime_suspend state, if I am correct. But ofcourse
> that could be the future.
Yes, there is, or more precisely there's going to be shortly. We have
PM domains on SH7372 and when we enable all of them to be powered off
at run time, there will be many power states for the controller which
is located in one of them. Hence the $subject patch. :-)
> Moreover, I definitely do not think that a fixed timeout of 100us is
> applicable for all use cases, this must at least be configurable.
Well, this isn't a timeout. Have you read my reply to Linus?
I agree that it should be configurable _eventually_, but no one seems to
know how to implement that configurability. Ideally, that value should
result from some user space input, possibly after a conversion by the
driver to a useful number, but we don't seem to have any agreement as to
what the interface for passing that user space input to the driver should
look like.
> >> However, we could also do pm_runtime_get_sync of the host device in
> >> claim host and vice verse in release host, thus preventing the host
> >> driver from triggering runtime_suspend|resume for every request. Though,
> >> I am not 100% sure this is really what you want either.
> >
> > No, I don't want that. I want the device to be suspended when possible,
> > but I don't want that to cause the system to go into an overly deep power
> > state as a result.
>
> Before just skipping my proposal, I think you should know some more
> background to why I suggested this:
>
> 1.
> mmc_claim_host is using mmc_host_enable, which kind of mean the same
> thing for a host driver as doing get_sync. Vice verse for mmc_release_host.
>
> 2.
> When executing mmc/sd commands/requests the host must always be claimed
> (and thus the host is always enabled). But more important some mmc/sd
> commands must be executed as a sequence, without the host being disabled
> in between the commands (since a disable might mean that the clock to
> card gets disabled). To solve this, the mmc_claim_host is used, to make
> sure the host is enabled during the complete command sequence.
>
> I happily continue this discussion, to see if someone more can break the
> idea about having get_sync in mmc_host_enable. :-)
I'll leave this one to Guennadi, if you don't mind. :-)
> >> Using PM QoS as you propose, might prevent some hosts from doing
> >> runtime_suspend|resume completely and thus those might not fulfill power
> >> consumption requirements instead.
> >
> > I'm not sure what scenario you have in mind. Care to elaborate?
>
> Well, suppose a the host drivers start considering the PM QoS
> requirement, but never can fulfill the requirement of 100us for it's
> runtime_suspend callback function...
OK, that's a valid concern. This means there should be a way for user space
to specify the constraint somehow, because it's a user space's role to define
policies.
> >> I do not think we can take this decision at this level. Is performance more
> >> important than power save, that is kind of the question.
> >
> > Yes, it is. Also, the number used here is somewhat arbitrary.
>
> For you maybe power management is less important, but I doubt everybody
> else agree to that. It is a more complex balance I believe.
You're right.
> > However, since no one except for SH7372 is now using device PM QoS, no one
> > else will be affected by this change at the moment.
>
> True, but that is not a good reason for adding more stuff to the mmc core.
Good point.
Thanks,
Rafael
^ permalink raw reply
* Re: [PATCH v4 REPOST 3/5] omap4: Unconditionally require l2x0 L2
From: Rob Herring @ 2011-12-14 21:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111214183952.GG32251@atomide.com>
On 12/14/2011 12:39 PM, Tony Lindgren wrote:
> * Dave Martin <dave.martin@linaro.org> [111214 09:58]:
>> On Wed, Dec 14, 2011 at 10:14:25AM -0800, Tony Lindgren wrote:
>>> * Dave Martin <dave.martin@linaro.org> [111214 03:08]:
>>>> If running in the Normal World on a TrustZone-enabled SoC, Linux
>>>> does not have complete control over the L2 cache controller
>>>> configuration. The kernel cannot work reliably on such platforms
>>>> without the l2x0 cache support code built in.
>>>
>>> There are HS and GP omaps (High Security and General Purpose).
>>> GP omaps do have full control of the L2. Also HS omaps most likely
>>> provide control over enabling and disabling L2 depending how the
>>> secure code is implemented.
>>>
>>> BTW, the real problem is that because the secure code is implemented
>>> in various ways, we don't really have any handling for it in Linux.
>>>
>>> The SMI instruction numbers don't seem to be standardized at all,
>>> and can mean different things on different boards, even different
>>> board versions :(
>>>
>>> Sounds like devicetree is the only safe way to deal with the L2
>>> control options.
>>>
>>> Regards,
>>>
>>> Tony
>>>
>>>
>>>> This patch unconditionally enables l2x0 support for the OMAP4 SoCs.
>>>>
>>>> Thanks to Rob Herring for this suggestion. [1]
>>>>
>>>> Signed-off-by: Dave Martin <dave.martin@linaro.org>
>>>>
>>>> [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074495.html
>>>> ---
>>>> arch/arm/mach-omap2/Kconfig | 2 +-
>>>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
>>>> index bb1b670..94e568a 100644
>>>> --- a/arch/arm/mach-omap2/Kconfig
>>>> +++ b/arch/arm/mach-omap2/Kconfig
>>>> @@ -41,11 +41,11 @@ config ARCH_OMAP4
>>>> bool "TI OMAP4"
>>>> default y
>>>> depends on ARCH_OMAP2PLUS
>>>> + select CACHE_L2X0
>>>> select CPU_V7
>>>> select ARM_GIC
>>>> select HAVE_SMP
>>>> select LOCAL_TIMERS if SMP
>>>> - select MIGHT_HAVE_CACHE_L2X0
>>>> select PL310_ERRATA_588369
>>>> select PL310_ERRATA_727915
>>>> select ARM_ERRATA_720789
>>>> --
>>>> 1.7.4.1
>>>>
>>
>> To clarify, are you suggesting we retain this patch, or not?
>
> I think we should keep L2 configurable for omaps until we have some
> way of getting the configuration dynamically or from device tree.
>
This already exists with l2x0_of_init. OMAP just needs to start using
it. It will initialize the l2 if present in the DT and skip it if not
present.
Rob
>> (If we only know what l2x0 support will be needed once the dts is
>> parsed at runtime, there could be an argument for keeping the
>> select CACHE_L2X0 here -- unless we have specific kconfigs for
>> the different security variants of omap.)
>
> Well we can detect if it's an HS omap, but we may not know what
> SMI it uses for enabling and disabling L2.. That can depend on
> the board version.
>
> Is there some problem keeping MIGHT_HAVE_CACHE_L2X0? This is
> pretty important from debugging cache issues point of view.
>
> Regards,
>
> Tony
^ permalink raw reply
* Re: [PATCH v4 REPOST 3/5] omap4: Unconditionally require l2x0 L2
From: Tony Lindgren @ 2011-12-14 18:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111214183030.GB9331@linaro.org>
* Dave Martin <dave.martin@linaro.org> [111214 09:58]:
> On Wed, Dec 14, 2011 at 10:14:25AM -0800, Tony Lindgren wrote:
> > * Dave Martin <dave.martin@linaro.org> [111214 03:08]:
> > > If running in the Normal World on a TrustZone-enabled SoC, Linux
> > > does not have complete control over the L2 cache controller
> > > configuration. The kernel cannot work reliably on such platforms
> > > without the l2x0 cache support code built in.
> >
> > There are HS and GP omaps (High Security and General Purpose).
> > GP omaps do have full control of the L2. Also HS omaps most likely
> > provide control over enabling and disabling L2 depending how the
> > secure code is implemented.
> >
> > BTW, the real problem is that because the secure code is implemented
> > in various ways, we don't really have any handling for it in Linux.
> >
> > The SMI instruction numbers don't seem to be standardized at all,
> > and can mean different things on different boards, even different
> > board versions :(
> >
> > Sounds like devicetree is the only safe way to deal with the L2
> > control options.
> >
> > Regards,
> >
> > Tony
> >
> >
> > > This patch unconditionally enables l2x0 support for the OMAP4 SoCs.
> > >
> > > Thanks to Rob Herring for this suggestion. [1]
> > >
> > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > >
> > > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074495.html
> > > ---
> > > arch/arm/mach-omap2/Kconfig | 2 +-
> > > 1 files changed, 1 insertions(+), 1 deletions(-)
> > >
> > > diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> > > index bb1b670..94e568a 100644
> > > --- a/arch/arm/mach-omap2/Kconfig
> > > +++ b/arch/arm/mach-omap2/Kconfig
> > > @@ -41,11 +41,11 @@ config ARCH_OMAP4
> > > bool "TI OMAP4"
> > > default y
> > > depends on ARCH_OMAP2PLUS
> > > + select CACHE_L2X0
> > > select CPU_V7
> > > select ARM_GIC
> > > select HAVE_SMP
> > > select LOCAL_TIMERS if SMP
> > > - select MIGHT_HAVE_CACHE_L2X0
> > > select PL310_ERRATA_588369
> > > select PL310_ERRATA_727915
> > > select ARM_ERRATA_720789
> > > --
> > > 1.7.4.1
> > >
>
> To clarify, are you suggesting we retain this patch, or not?
I think we should keep L2 configurable for omaps until we have some
way of getting the configuration dynamically or from device tree.
> (If we only know what l2x0 support will be needed once the dts is
> parsed at runtime, there could be an argument for keeping the
> select CACHE_L2X0 here -- unless we have specific kconfigs for
> the different security variants of omap.)
Well we can detect if it's an HS omap, but we may not know what
SMI it uses for enabling and disabling L2.. That can depend on
the board version.
Is there some problem keeping MIGHT_HAVE_CACHE_L2X0? This is
pretty important from debugging cache issues point of view.
Regards,
Tony
^ permalink raw reply
* [PATCH 4/4] mmc: sh_mmcif: remove now superfluous sh_mmcif_host::data member
From: Guennadi Liakhovetski @ 2011-12-14 18:31 UTC (permalink / raw)
To: linux-mmc; +Cc: linux-sh, Chris Ball, Magnus Damm
In-Reply-To: <Pine.LNX.4.64.1111301553330.22197@axis700.grange>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mmc/host/sh_mmcif.c | 94 +++++++++++++++++++++++--------------------
1 files changed, 50 insertions(+), 44 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index ec6805c..29bcb75 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -207,7 +207,6 @@ enum mmcif_wait_for {
struct sh_mmcif_host {
struct mmc_host *mmc;
- struct mmc_data *data;
struct mmc_request *mrq;
struct platform_device *pd;
struct clk *hclk;
@@ -250,19 +249,21 @@ static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
static void mmcif_dma_complete(void *arg)
{
struct sh_mmcif_host *host = arg;
+ struct mmc_data *data = host->mrq->data;
+
dev_dbg(&host->pd->dev, "Command completed\n");
- if (WARN(!host->data, "%s: NULL data in DMA completion!\n",
+ if (WARN(!data, "%s: NULL data in DMA completion!\n",
dev_name(&host->pd->dev)))
return;
- if (host->data->flags & MMC_DATA_READ)
+ if (data->flags & MMC_DATA_READ)
dma_unmap_sg(host->chan_rx->device->dev,
- host->data->sg, host->data->sg_len,
+ data->sg, data->sg_len,
DMA_FROM_DEVICE);
else
dma_unmap_sg(host->chan_tx->device->dev,
- host->data->sg, host->data->sg_len,
+ data->sg, data->sg_len,
DMA_TO_DEVICE);
complete(&host->dma_complete);
@@ -270,13 +271,14 @@ static void mmcif_dma_complete(void *arg)
static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
{
- struct scatterlist *sg = host->data->sg;
+ struct mmc_data *data = host->mrq->data;
+ struct scatterlist *sg = data->sg;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_rx;
dma_cookie_t cookie = -EINVAL;
int ret;
- ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+ ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
DMA_FROM_DEVICE);
if (ret > 0) {
host->dma_active = true;
@@ -292,7 +294,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
dma_async_issue_pending(chan);
}
dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
- __func__, host->data->sg_len, ret, cookie);
+ __func__, data->sg_len, ret, cookie);
if (!desc) {
/* DMA failed, fall back to PIO */
@@ -313,18 +315,19 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
}
dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
- desc, cookie, host->data->sg_len);
+ desc, cookie, data->sg_len);
}
static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
{
- struct scatterlist *sg = host->data->sg;
+ struct mmc_data *data = host->mrq->data;
+ struct scatterlist *sg = data->sg;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_tx;
dma_cookie_t cookie = -EINVAL;
int ret;
- ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len,
+ ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
DMA_TO_DEVICE);
if (ret > 0) {
host->dma_active = true;
@@ -340,7 +343,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
dma_async_issue_pending(chan);
}
dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
- __func__, host->data->sg_len, ret, cookie);
+ __func__, data->sg_len, ret, cookie);
if (!desc) {
/* DMA failed, fall back to PIO */
@@ -698,8 +701,11 @@ static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
}
static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
+ struct mmc_request *mrq)
{
+ struct mmc_data *data = mrq->data;
+ struct mmc_command *cmd = mrq->cmd;
+ u32 opc = cmd->opcode;
u32 tmp = 0;
/* Response Type check */
@@ -731,7 +737,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
break;
}
/* WDAT / DATW */
- if (host->data) {
+ if (data) {
tmp |= CMD_SET_WDAT;
switch (host->bus_width) {
case MMC_BUS_WIDTH_1:
@@ -755,7 +761,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
if (opc = MMC_READ_MULTIPLE_BLOCK || opc = MMC_WRITE_MULTIPLE_BLOCK) {
tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
- mrq->data->blocks << 16);
+ data->blocks << 16);
}
/* RIDXC[1:0] check bits */
if (opc = MMC_SEND_OP_COND || opc = MMC_ALL_SEND_CID ||
@@ -769,7 +775,7 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
opc = MMC_SEND_CSD || opc = MMC_SEND_CID)
tmp |= CMD_SET_CRC7C_INTERNAL;
- return opc = ((opc << 24) | tmp);
+ return (opc << 24) | tmp;
}
static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
@@ -817,12 +823,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
break;
}
- if (host->data) {
+ if (mrq->data) {
sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
mrq->data->blksz);
}
- opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
+ opc = sh_mmcif_set_cmd(host, mrq);
sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
@@ -838,15 +844,16 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
struct mmc_request *mrq)
{
- struct mmc_command *cmd = mrq->stop;
-
- if (mrq->cmd->opcode = MMC_READ_MULTIPLE_BLOCK)
+ switch (mrq->cmd->opcode) {
+ case MMC_READ_MULTIPLE_BLOCK:
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
- else if (mrq->cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK)
+ break;
+ case MMC_WRITE_MULTIPLE_BLOCK:
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
- else {
+ break;
+ default:
dev_err(&host->pd->dev, "unsupported stop cmd\n");
- cmd->error = sh_mmcif_error_manage(host);
+ mrq->stop->error = sh_mmcif_error_manage(host);
return;
}
@@ -892,7 +899,6 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->mrq = mrq;
- host->data = mrq->data;
sh_mmcif_start_cmd(host, mrq);
}
@@ -972,6 +978,7 @@ static struct mmc_host_ops sh_mmcif_ops = {
static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
{
struct mmc_command *cmd = host->mrq->cmd;
+ struct mmc_data *data = host->mrq->data;
long time;
if (host->sd_error) {
@@ -997,10 +1004,10 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
sh_mmcif_get_response(host, cmd);
- if (!host->data)
+ if (!data)
return false;
- if (host->mrq->data->flags & MMC_DATA_READ) {
+ if (data->flags & MMC_DATA_READ) {
if (host->chan_rx)
sh_mmcif_start_dma_rx(host);
} else {
@@ -1009,8 +1016,8 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
}
if (!host->dma_active) {
- host->data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
- if (!host->data->error)
+ data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
+ if (!data->error)
return true;
return false;
}
@@ -1022,22 +1029,22 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
dev_err(host->mmc->parent,
"Error IRQ while waiting for DMA completion!\n");
/* Woken up by an error IRQ: abort DMA */
- if (host->data->flags & MMC_DATA_READ)
+ if (data->flags & MMC_DATA_READ)
dmaengine_terminate_all(host->chan_rx);
else
dmaengine_terminate_all(host->chan_tx);
- host->data->error = sh_mmcif_error_manage(host);
+ data->error = sh_mmcif_error_manage(host);
} else if (!time) {
- host->data->error = -ETIMEDOUT;
+ data->error = -ETIMEDOUT;
} else if (time < 0) {
- host->data->error = time;
+ data->error = time;
}
sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
host->dma_active = false;
- if (host->data->error)
- host->data->bytes_xfered = 0;
+ if (data->error)
+ data->bytes_xfered = 0;
return false;
}
@@ -1046,6 +1053,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
struct mmc_request *mrq = host->mrq;
+ struct mmc_data *data = mrq->data;
cancel_delayed_work_sync(&host->timeout_work);
@@ -1093,20 +1101,18 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
case MMCIF_WAIT_FOR_READ_END:
case MMCIF_WAIT_FOR_WRITE_END:
if (host->sd_error)
- mrq->data->error = sh_mmcif_error_manage(host);
+ data->error = sh_mmcif_error_manage(host);
break;
default:
BUG();
}
if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
- host->data = NULL;
+ if (!mrq->cmd->error && data && !data->error)
+ data->bytes_xfered + data->blocks * data->blksz;
- if (!mrq->cmd->error && mrq->data && !mrq->data->error)
- mrq->data->bytes_xfered - mrq->data->blocks * mrq->data->blksz;
-
- if (mrq->stop && !mrq->cmd->error && (!mrq->data || !mrq->data->error)) {
+ if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
sh_mmcif_stop_cmd(host, mrq);
if (!mrq->stop->error)
return IRQ_HANDLED;
@@ -1115,6 +1121,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
host->wait_for = MMCIF_WAIT_FOR_REQUEST;
host->state = STATE_IDLE;
+ host->mrq = NULL;
mmc_request_done(host->mmc, mrq);
return IRQ_HANDLED;
@@ -1210,7 +1217,7 @@ static void mmcif_timeout_work(struct work_struct *work)
case MMCIF_WAIT_FOR_WRITE:
case MMCIF_WAIT_FOR_READ_END:
case MMCIF_WAIT_FOR_WRITE_END:
- host->data->error = sh_mmcif_error_manage(host);
+ mrq->data->error = sh_mmcif_error_manage(host);
break;
default:
BUG();
@@ -1218,7 +1225,6 @@ static void mmcif_timeout_work(struct work_struct *work)
host->state = STATE_IDLE;
host->wait_for = MMCIF_WAIT_FOR_REQUEST;
- host->data = NULL;
host->mrq = NULL;
mmc_request_done(host->mmc, mrq);
}
--
1.7.2.5
^ permalink raw reply related
* [PATCH 3/4 v2] mmc: sh_mmcif: process requests asynchronously
From: Guennadi Liakhovetski @ 2011-12-14 18:31 UTC (permalink / raw)
To: linux-mmc; +Cc: linux-sh, Chris Ball, Magnus Damm
In-Reply-To: <Pine.LNX.4.64.1111301553330.22197@axis700.grange>
This patch converts the sh_mmcif MMC host driver to process requests
asynchronously instead of waiting in its .request() method for completion.
This is achieved by using threaded IRQs.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mmc/host/sh_mmcif.c | 588 ++++++++++++++++++++++++++++++-------------
1 files changed, 416 insertions(+), 172 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index d6a534c..ec6805c 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -16,6 +16,32 @@
*
*/
+/*
+ * The MMCIF driver is now processing MMC requests asynchronously, according
+ * to the Linux MMC API requirement.
+ *
+ * The MMCIF driver processes MMC requests in up to 3 stages: command, optional
+ * data, and optional stop. To achieve asynchronous processing each of these
+ * stages is split into two halves: a top and a bottom half. The top half
+ * initialises the hardware, installs a timeout handler to handle completion
+ * timeouts, and returns. In case of the command stage this immediately returns
+ * control to the caller, leaving all further processing to run asynchronously.
+ * All further request processing is performed by the bottom halves.
+ *
+ * The bottom half further consists of a "hard" IRQ handler, an IRQ handler
+ * thread, a DMA completion callback, if DMA is used, a timeout work, and
+ * request- and stage-specific handler methods.
+ *
+ * Each bottom half run begins with either a hardware interrupt, a DMA callback
+ * invocation, or a timeout work run. In case of an error or a successful
+ * processing completion, the MMC core is informed and the request processing is
+ * finished. In case processing has to continue, i.e., if data has to be read
+ * from or written to the card, or if a stop command has to be sent, the next
+ * top half is called, which performs the necessary hardware handling and
+ * reschedules the timeout work. This returns the driver state machine into the
+ * bottom half waiting state.
+ */
+
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
@@ -167,19 +193,38 @@ enum mmcif_state {
STATE_IOS,
};
+enum mmcif_wait_for {
+ MMCIF_WAIT_FOR_REQUEST,
+ MMCIF_WAIT_FOR_CMD,
+ MMCIF_WAIT_FOR_MREAD,
+ MMCIF_WAIT_FOR_MWRITE,
+ MMCIF_WAIT_FOR_READ,
+ MMCIF_WAIT_FOR_WRITE,
+ MMCIF_WAIT_FOR_READ_END,
+ MMCIF_WAIT_FOR_WRITE_END,
+ MMCIF_WAIT_FOR_STOP,
+};
+
struct sh_mmcif_host {
struct mmc_host *mmc;
struct mmc_data *data;
+ struct mmc_request *mrq;
struct platform_device *pd;
struct clk *hclk;
unsigned int clk;
int bus_width;
bool sd_error;
+ bool dying;
long timeout;
void __iomem *addr;
- struct completion intr_wait;
+ u32 *pio_ptr;
spinlock_t lock; /* protect sh_mmcif_host::state */
enum mmcif_state state;
+ enum mmcif_wait_for wait_for;
+ struct delayed_work timeout_work;
+ size_t blocksize;
+ int sg_idx;
+ int sg_blkidx;
bool power;
bool card_present;
@@ -455,125 +500,183 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
return ret;
}
-static int sh_mmcif_single_read(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
+static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p)
{
- struct mmc_data *data = mrq->data;
- long time;
- u32 blocksize, i, *p = sg_virt(data->sg);
+ struct mmc_data *data = host->mrq->data;
+
+ host->sg_blkidx += host->blocksize;
+
+ /* data->sg->length must be a multiple of host->blocksize? */
+ BUG_ON(host->sg_blkidx > data->sg->length);
+
+ if (host->sg_blkidx = data->sg->length) {
+ host->sg_blkidx = 0;
+ if (++host->sg_idx < data->sg_len)
+ host->pio_ptr = sg_virt(++data->sg);
+ } else {
+ host->pio_ptr = p;
+ }
+
+ if (host->sg_idx = data->sg_len)
+ return false;
+
+ return true;
+}
+
+static void sh_mmcif_single_read(struct sh_mmcif_host *host,
+ struct mmc_request *mrq)
+{
+ host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+ BLOCK_SIZE_MASK) + 3;
+
+ host->wait_for = MMCIF_WAIT_FOR_READ;
+ schedule_delayed_work(&host->timeout_work, host->timeout);
/* buf read enable */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
-
- blocksize = (BLOCK_SIZE_MASK &
- sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
- for (i = 0; i < blocksize / 4; i++)
+}
+
+static bool sh_mmcif_read_block(struct sh_mmcif_host *host)
+{
+ struct mmc_data *data = host->mrq->data;
+ u32 *p = sg_virt(data->sg);
+ int i;
+
+ if (host->sd_error) {
+ data->error = sh_mmcif_error_manage(host);
+ return false;
+ }
+
+ for (i = 0; i < host->blocksize / 4; i++)
*p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
/* buffer read end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
+ host->wait_for = MMCIF_WAIT_FOR_READ_END;
- return 0;
+ return true;
}
-static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
+static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
+ struct mmc_request *mrq)
{
struct mmc_data *data = mrq->data;
- long time;
- u32 blocksize, i, j, sec, *p;
-
- blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
- MMCIF_CE_BLOCK_SET);
- for (j = 0; j < data->sg_len; j++) {
- p = sg_virt(data->sg);
- for (sec = 0; sec < data->sg->length / blocksize; sec++) {
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
- /* buf read enable */
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
-
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
-
- for (i = 0; i < blocksize / 4; i++)
- *p++ = sh_mmcif_readl(host->addr,
- MMCIF_CE_DATA);
- }
- if (j < data->sg_len - 1)
- data->sg++;
+
+ if (!data->sg_len || !data->sg->length)
+ return;
+
+ host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+ BLOCK_SIZE_MASK;
+
+ host->wait_for = MMCIF_WAIT_FOR_MREAD;
+ host->sg_idx = 0;
+ host->sg_blkidx = 0;
+ host->pio_ptr = sg_virt(data->sg);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+}
+
+static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
+{
+ struct mmc_data *data = host->mrq->data;
+ u32 *p = host->pio_ptr;
+ int i;
+
+ if (host->sd_error) {
+ data->error = sh_mmcif_error_manage(host);
+ return false;
}
- return 0;
+
+ BUG_ON(!data->sg->length);
+
+ for (i = 0; i < host->blocksize / 4; i++)
+ *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
+
+ if (!sh_mmcif_next_block(host, p))
+ return false;
+
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+
+ return true;
}
-static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+static void sh_mmcif_single_write(struct sh_mmcif_host *host,
struct mmc_request *mrq)
{
- struct mmc_data *data = mrq->data;
- long time;
- u32 blocksize, i, *p = sg_virt(data->sg);
+ host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+ BLOCK_SIZE_MASK) + 3;
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+ host->wait_for = MMCIF_WAIT_FOR_WRITE;
+ schedule_delayed_work(&host->timeout_work, host->timeout);
/* buf write enable */
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
-
- blocksize = (BLOCK_SIZE_MASK &
- sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
- for (i = 0; i < blocksize / 4; i++)
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
+
+static bool sh_mmcif_write_block(struct sh_mmcif_host *host)
+{
+ struct mmc_data *data = host->mrq->data;
+ u32 *p = sg_virt(data->sg);
+ int i;
+
+ if (host->sd_error) {
+ data->error = sh_mmcif_error_manage(host);
+ return false;
+ }
+
+ for (i = 0; i < host->blocksize / 4; i++)
sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
/* buffer write end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+ host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
-
- return 0;
+ return true;
}
-static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
+static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
+ struct mmc_request *mrq)
{
struct mmc_data *data = mrq->data;
- long time;
- u32 i, sec, j, blocksize, *p;
- blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
- MMCIF_CE_BLOCK_SET);
+ if (!data->sg_len || !data->sg->length)
+ return;
- for (j = 0; j < data->sg_len; j++) {
- p = sg_virt(data->sg);
- for (sec = 0; sec < data->sg->length / blocksize; sec++) {
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
- /* buf write enable*/
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
+ host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
+ BLOCK_SIZE_MASK;
- if (time <= 0 || host->sd_error)
- return sh_mmcif_error_manage(host);
+ host->wait_for = MMCIF_WAIT_FOR_MWRITE;
+ host->sg_idx = 0;
+ host->sg_blkidx = 0;
+ host->pio_ptr = sg_virt(data->sg);
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+}
- for (i = 0; i < blocksize / 4; i++)
- sh_mmcif_writel(host->addr,
- MMCIF_CE_DATA, *p++);
- }
- if (j < data->sg_len - 1)
- data->sg++;
+static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)
+{
+ struct mmc_data *data = host->mrq->data;
+ u32 *p = host->pio_ptr;
+ int i;
+
+ if (host->sd_error) {
+ data->error = sh_mmcif_error_manage(host);
+ return false;
}
- return 0;
+
+ BUG_ON(!data->sg->length);
+
+ for (i = 0; i < host->blocksize / 4; i++)
+ sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
+
+ if (!sh_mmcif_next_block(host, p))
+ return false;
+
+ schedule_delayed_work(&host->timeout_work, host->timeout);
+ sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+
+ return true;
}
static void sh_mmcif_get_response(struct sh_mmcif_host *host,
@@ -670,18 +773,22 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
}
static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
- struct mmc_request *mrq, u32 opc)
+ struct mmc_request *mrq, u32 opc)
{
switch (opc) {
case MMC_READ_MULTIPLE_BLOCK:
- return sh_mmcif_multi_read(host, mrq);
+ sh_mmcif_multi_read(host, mrq);
+ return 0;
case MMC_WRITE_MULTIPLE_BLOCK:
- return sh_mmcif_multi_write(host, mrq);
+ sh_mmcif_multi_write(host, mrq);
+ return 0;
case MMC_WRITE_BLOCK:
- return sh_mmcif_single_write(host, mrq);
+ sh_mmcif_single_write(host, mrq);
+ return 0;
case MMC_READ_SINGLE_BLOCK:
case MMC_SEND_EXT_CSD:
- return sh_mmcif_single_read(host, mrq);
+ sh_mmcif_single_read(host, mrq);
+ return 0;
default:
dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
return -EINVAL;
@@ -692,9 +799,8 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->cmd;
- long time;
- int ret = 0;
- u32 mask, opc = cmd->opcode;
+ u32 opc = cmd->opcode;
+ u32 mask;
switch (opc) {
/* response busy check */
@@ -725,62 +831,14 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
/* set cmd */
sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0) {
- cmd->error = sh_mmcif_error_manage(host);
- return;
- }
- if (host->sd_error) {
- switch (cmd->opcode) {
- case MMC_ALL_SEND_CID:
- case MMC_SELECT_CARD:
- case MMC_APP_CMD:
- cmd->error = -ETIMEDOUT;
- break;
- default:
- dev_dbg(&host->pd->dev, "Cmd(d'%d) err\n",
- cmd->opcode);
- cmd->error = sh_mmcif_error_manage(host);
- break;
- }
- host->sd_error = false;
- return;
- }
- if (!(cmd->flags & MMC_RSP_PRESENT)) {
- cmd->error = 0;
- return;
- }
- sh_mmcif_get_response(host, cmd);
- if (host->data) {
- if (!host->dma_active) {
- ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
- } else {
- long time - wait_for_completion_interruptible_timeout(&host->dma_complete,
- host->timeout);
- if (!time)
- ret = -ETIMEDOUT;
- else if (time < 0)
- ret = time;
- sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
- BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
- host->dma_active = false;
- }
- if (ret < 0)
- mrq->data->bytes_xfered = 0;
- else
- mrq->data->bytes_xfered - mrq->data->blocks * mrq->data->blksz;
- }
- cmd->error = ret;
+ host->wait_for = MMCIF_WAIT_FOR_CMD;
+ schedule_delayed_work(&host->timeout_work, host->timeout);
}
static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd = mrq->stop;
- long time;
if (mrq->cmd->opcode = MMC_READ_MULTIPLE_BLOCK)
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
@@ -792,14 +850,8 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
return;
}
- time = wait_for_completion_interruptible_timeout(&host->intr_wait,
- host->timeout);
- if (time <= 0 || host->sd_error) {
- cmd->error = sh_mmcif_error_manage(host);
- return;
- }
- sh_mmcif_get_cmd12response(host, cmd);
- cmd->error = 0;
+ host->wait_for = MMCIF_WAIT_FOR_STOP;
+ schedule_delayed_work(&host->timeout_work, host->timeout);
}
static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
@@ -838,23 +890,11 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
default:
break;
}
+
+ host->mrq = mrq;
host->data = mrq->data;
- if (mrq->data) {
- if (mrq->data->flags & MMC_DATA_READ) {
- if (host->chan_rx)
- sh_mmcif_start_dma_rx(host);
- } else {
- if (host->chan_tx)
- sh_mmcif_start_dma_tx(host);
- }
- }
- sh_mmcif_start_cmd(host, mrq);
- host->data = NULL;
- if (!mrq->cmd->error && mrq->stop)
- sh_mmcif_stop_cmd(host, mrq);
- host->state = STATE_IDLE;
- mmc_request_done(mmc, mrq);
+ sh_mmcif_start_cmd(host, mrq);
}
static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -929,6 +969,157 @@ static struct mmc_host_ops sh_mmcif_ops = {
.get_cd = sh_mmcif_get_cd,
};
+static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
+{
+ struct mmc_command *cmd = host->mrq->cmd;
+ long time;
+
+ if (host->sd_error) {
+ switch (cmd->opcode) {
+ case MMC_ALL_SEND_CID:
+ case MMC_SELECT_CARD:
+ case MMC_APP_CMD:
+ cmd->error = -ETIMEDOUT;
+ host->sd_error = false;
+ break;
+ default:
+ cmd->error = sh_mmcif_error_manage(host);
+ dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n",
+ cmd->opcode, cmd->error);
+ break;
+ }
+ return false;
+ }
+ if (!(cmd->flags & MMC_RSP_PRESENT)) {
+ cmd->error = 0;
+ return false;
+ }
+
+ sh_mmcif_get_response(host, cmd);
+
+ if (!host->data)
+ return false;
+
+ if (host->mrq->data->flags & MMC_DATA_READ) {
+ if (host->chan_rx)
+ sh_mmcif_start_dma_rx(host);
+ } else {
+ if (host->chan_tx)
+ sh_mmcif_start_dma_tx(host);
+ }
+
+ if (!host->dma_active) {
+ host->data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
+ if (!host->data->error)
+ return true;
+ return false;
+ }
+
+ /* Running in the IRQ thread, can sleep */
+ time = wait_for_completion_interruptible_timeout(&host->dma_complete,
+ host->timeout);
+ if (host->sd_error) {
+ dev_err(host->mmc->parent,
+ "Error IRQ while waiting for DMA completion!\n");
+ /* Woken up by an error IRQ: abort DMA */
+ if (host->data->flags & MMC_DATA_READ)
+ dmaengine_terminate_all(host->chan_rx);
+ else
+ dmaengine_terminate_all(host->chan_tx);
+ host->data->error = sh_mmcif_error_manage(host);
+ } else if (!time) {
+ host->data->error = -ETIMEDOUT;
+ } else if (time < 0) {
+ host->data->error = time;
+ }
+ sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
+ BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
+ host->dma_active = false;
+
+ if (host->data->error)
+ host->data->bytes_xfered = 0;
+
+ return false;
+}
+
+static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
+{
+ struct sh_mmcif_host *host = dev_id;
+ struct mmc_request *mrq = host->mrq;
+
+ cancel_delayed_work_sync(&host->timeout_work);
+
+ /*
+ * All handlers return true, if processing continues, and false, if the
+ * request has to be completed - successfully or not
+ */
+ switch (host->wait_for) {
+ case MMCIF_WAIT_FOR_REQUEST:
+ /* We're too late, the timeout has already kicked in */
+ return IRQ_HANDLED;
+ case MMCIF_WAIT_FOR_CMD:
+ if (sh_mmcif_end_cmd(host))
+ /* Wait for data */
+ return IRQ_HANDLED;
+ break;
+ case MMCIF_WAIT_FOR_MREAD:
+ if (sh_mmcif_mread_block(host))
+ /* Wait for more data */
+ return IRQ_HANDLED;
+ break;
+ case MMCIF_WAIT_FOR_READ:
+ if (sh_mmcif_read_block(host))
+ /* Wait for data end */
+ return IRQ_HANDLED;
+ break;
+ case MMCIF_WAIT_FOR_MWRITE:
+ if (sh_mmcif_mwrite_block(host))
+ /* Wait data to write */
+ return IRQ_HANDLED;
+ break;
+ case MMCIF_WAIT_FOR_WRITE:
+ if (sh_mmcif_write_block(host))
+ /* Wait for data end */
+ return IRQ_HANDLED;
+ break;
+ case MMCIF_WAIT_FOR_STOP:
+ if (host->sd_error) {
+ mrq->stop->error = sh_mmcif_error_manage(host);
+ break;
+ }
+ sh_mmcif_get_cmd12response(host, mrq->stop);
+ mrq->stop->error = 0;
+ break;
+ case MMCIF_WAIT_FOR_READ_END:
+ case MMCIF_WAIT_FOR_WRITE_END:
+ if (host->sd_error)
+ mrq->data->error = sh_mmcif_error_manage(host);
+ break;
+ default:
+ BUG();
+ }
+
+ if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
+ host->data = NULL;
+
+ if (!mrq->cmd->error && mrq->data && !mrq->data->error)
+ mrq->data->bytes_xfered + mrq->data->blocks * mrq->data->blksz;
+
+ if (mrq->stop && !mrq->cmd->error && (!mrq->data || !mrq->data->error)) {
+ sh_mmcif_stop_cmd(host, mrq);
+ if (!mrq->stop->error)
+ return IRQ_HANDLED;
+ }
+ }
+
+ host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+ host->state = STATE_IDLE;
+ mmc_request_done(host->mmc, mrq);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
@@ -980,14 +1171,58 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
host->sd_error = true;
dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
}
- if (state & ~(INT_CMD12RBE | INT_CMD12CRE))
- complete(&host->intr_wait);
- else
+ if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
+ if (!host->dma_active)
+ return IRQ_WAKE_THREAD;
+ else if (host->sd_error)
+ mmcif_dma_complete(host);
+ } else {
dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
+ }
return IRQ_HANDLED;
}
+static void mmcif_timeout_work(struct work_struct *work)
+{
+ struct delayed_work *d = container_of(work, struct delayed_work, work);
+ struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work);
+ struct mmc_request *mrq = host->mrq;
+
+ if (host->dying)
+ /* Don't run after mmc_remove_host() */
+ return;
+
+ /*
+ * Handle races with cancel_delayed_work(), unless
+ * cancel_delayed_work_sync() is used
+ */
+ switch (host->wait_for) {
+ case MMCIF_WAIT_FOR_CMD:
+ mrq->cmd->error = sh_mmcif_error_manage(host);
+ break;
+ case MMCIF_WAIT_FOR_STOP:
+ mrq->stop->error = sh_mmcif_error_manage(host);
+ break;
+ case MMCIF_WAIT_FOR_MREAD:
+ case MMCIF_WAIT_FOR_MWRITE:
+ case MMCIF_WAIT_FOR_READ:
+ case MMCIF_WAIT_FOR_WRITE:
+ case MMCIF_WAIT_FOR_READ_END:
+ case MMCIF_WAIT_FOR_WRITE_END:
+ host->data->error = sh_mmcif_error_manage(host);
+ break;
+ default:
+ BUG();
+ }
+
+ host->state = STATE_IDLE;
+ host->wait_for = MMCIF_WAIT_FOR_REQUEST;
+ host->data = NULL;
+ host->mrq = NULL;
+ mmc_request_done(host->mmc, mrq);
+}
+
static int __devinit sh_mmcif_probe(struct platform_device *pdev)
{
int ret = 0, irq[2];
@@ -1041,7 +1276,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
host->clk = clk_get_rate(host->hclk);
host->pd = pdev;
- init_completion(&host->intr_wait);
spin_lock_init(&host->lock);
mmc->ops = &sh_mmcif_ops;
@@ -1078,18 +1312,20 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
- ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
+ ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
if (ret) {
dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
goto clean_up3;
}
- ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
+ ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
if (ret) {
free_irq(irq[0], host);
dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
goto clean_up3;
}
+ INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
+
mmc_detect_change(host->mmc, 0);
dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
@@ -1116,11 +1352,19 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
int irq[2];
+ host->dying = true;
pm_runtime_get_sync(&pdev->dev);
mmc_remove_host(host->mmc);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+ /*
+ * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the
+ * mmc_remove_host() call above. But swapping order doesn't help either
+ * (a query on the linux-mmc mailing list didn't bring any replies).
+ */
+ cancel_delayed_work_sync(&host->timeout_work);
+
if (host->addr)
iounmap(host->addr);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 2/4 v2] mmc: sh_mmcif: cosmetic clean up
From: Guennadi Liakhovetski @ 2011-12-14 18:31 UTC (permalink / raw)
To: linux-mmc; +Cc: linux-sh, Chris Ball, Magnus Damm
In-Reply-To: <Pine.LNX.4.64.1111301553330.22197@axis700.grange>
This patch doesn't introduce any functional changes, it only simplifies
some code fragments, removes superfluous parameters, fixes typos.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mmc/host/sh_mmcif.c | 79 ++++++++++++++++++------------------------
1 files changed, 34 insertions(+), 45 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 63559d6..d6a534c 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -123,6 +123,11 @@
#define MASK_MRBSYTO (1 << 1)
#define MASK_MRSPTO (1 << 0)
+#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \
+ MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \
+ MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \
+ MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO)
+
/* CE_HOST_STS1 */
#define STS1_CMDSEQ (1 << 31)
@@ -173,8 +178,8 @@ struct sh_mmcif_host {
long timeout;
void __iomem *addr;
struct completion intr_wait;
+ spinlock_t lock; /* protect sh_mmcif_host::state */
enum mmcif_state state;
- spinlock_t lock;
bool power;
bool card_present;
@@ -409,7 +414,7 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
{
u32 state1, state2;
- int ret, timeout = 10000000;
+ int ret, timeout;
host->sd_error = false;
@@ -421,31 +426,30 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
if (state1 & STS1_CMDSEQ) {
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
- while (1) {
- timeout--;
- if (timeout < 0) {
- dev_err(&host->pd->dev,
- "Forceed end of command sequence timeout err\n");
- return -EIO;
- }
+ for (timeout = 10000000; timeout; timeout--) {
if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
- & STS1_CMDSEQ))
+ & STS1_CMDSEQ))
break;
mdelay(1);
}
+ if (!timeout) {
+ dev_err(&host->pd->dev,
+ "Forced end of command sequence timeout err\n");
+ return -EIO;
+ }
sh_mmcif_sync_reset(host);
dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
return -EIO;
}
if (state2 & STS2_CRC_ERR) {
- dev_dbg(&host->pd->dev, ": Happened CRC error\n");
+ dev_dbg(&host->pd->dev, ": CRC error\n");
ret = -EIO;
} else if (state2 & STS2_TIMEOUT_ERR) {
- dev_dbg(&host->pd->dev, ": Happened Timeout error\n");
+ dev_dbg(&host->pd->dev, ": Timeout\n");
ret = -ETIMEDOUT;
} else {
- dev_dbg(&host->pd->dev, ": Happened End/Index error\n");
+ dev_dbg(&host->pd->dev, ": End/Index error\n");
ret = -EIO;
}
return ret;
@@ -668,55 +672,44 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
struct mmc_request *mrq, u32 opc)
{
- int ret;
-
switch (opc) {
case MMC_READ_MULTIPLE_BLOCK:
- ret = sh_mmcif_multi_read(host, mrq);
- break;
+ return sh_mmcif_multi_read(host, mrq);
case MMC_WRITE_MULTIPLE_BLOCK:
- ret = sh_mmcif_multi_write(host, mrq);
- break;
+ return sh_mmcif_multi_write(host, mrq);
case MMC_WRITE_BLOCK:
- ret = sh_mmcif_single_write(host, mrq);
- break;
+ return sh_mmcif_single_write(host, mrq);
case MMC_READ_SINGLE_BLOCK:
case MMC_SEND_EXT_CSD:
- ret = sh_mmcif_single_read(host, mrq);
- break;
+ return sh_mmcif_single_read(host, mrq);
default:
dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- return ret;
}
static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq, struct mmc_command *cmd)
+ struct mmc_request *mrq)
{
+ struct mmc_command *cmd = mrq->cmd;
long time;
- int ret = 0, mask = 0;
- u32 opc = cmd->opcode;
+ int ret = 0;
+ u32 mask, opc = cmd->opcode;
switch (opc) {
- /* respons busy check */
+ /* response busy check */
case MMC_SWITCH:
case MMC_STOP_TRANSMISSION:
case MMC_SET_WRITE_PROT:
case MMC_CLR_WRITE_PROT:
case MMC_ERASE:
case MMC_GEN_CMD:
- mask = MASK_MRBSYE;
+ mask = MASK_START_CMD | MASK_MRBSYE;
break;
default:
- mask = MASK_MCRSPE;
+ mask = MASK_START_CMD | MASK_MCRSPE;
break;
}
- mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
- MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
- MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
- MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
if (host->data) {
sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
@@ -784,8 +777,9 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
}
static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq, struct mmc_command *cmd)
+ struct mmc_request *mrq)
{
+ struct mmc_command *cmd = mrq->stop;
long time;
if (mrq->cmd->opcode = MMC_READ_MULTIPLE_BLOCK)
@@ -854,11 +848,11 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
sh_mmcif_start_dma_tx(host);
}
}
- sh_mmcif_start_cmd(host, mrq, mrq->cmd);
+ sh_mmcif_start_cmd(host, mrq);
host->data = NULL;
if (!mrq->cmd->error && mrq->stop)
- sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+ sh_mmcif_stop_cmd(host, mrq);
host->state = STATE_IDLE;
mmc_request_done(mmc, mrq);
}
@@ -935,11 +929,6 @@ static struct mmc_host_ops sh_mmcif_ops = {
.get_cd = sh_mmcif_get_cd,
};
-static void sh_mmcif_detect(struct mmc_host *mmc)
-{
- mmc_detect_change(mmc, 0);
-}
-
static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
@@ -1101,7 +1090,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
goto clean_up3;
}
- sh_mmcif_detect(host->mmc);
+ mmc_detect_change(host->mmc, 0);
dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
dev_dbg(&pdev->dev, "chip ver H'%04x\n",
--
1.7.2.5
^ permalink raw reply related
* [PATCH 1/4] mmc: sh_mmcif: process error interrupts first
From: Guennadi Liakhovetski @ 2011-12-14 18:31 UTC (permalink / raw)
To: linux-mmc; +Cc: linux-sh, Chris Ball, Magnus Damm
In-Reply-To: <Pine.LNX.4.64.1111301553330.22197@axis700.grange>
If an interrupt is coming with both error and data completion status bits
set, it has to be handled as an error interrupt, for which error interrupts
have to be processed first. The current version of the driver on the
contrary doesn't recognise such interrupts as an error event, which leads
to data corruption and breaks the error recovery.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---
drivers/mmc/host/sh_mmcif.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index 824fee5..63559d6 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -948,7 +948,12 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
- if (state & INT_RBSYE) {
+ if (state & INT_ERR_STS) {
+ /* error interrupts - process first */
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
+ sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
+ err = 1;
+ } else if (state & INT_RBSYE) {
sh_mmcif_writel(host->addr, MMCIF_CE_INT,
~(INT_RBSYE | INT_CRSPE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
@@ -976,11 +981,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
sh_mmcif_writel(host->addr, MMCIF_CE_INT,
~(INT_CMD12RBE | INT_CMD12CRE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
- } else if (state & INT_ERR_STS) {
- /* err interrupts */
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
- err = 1;
} else {
dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 0/4 v2] mmc_ sh_mmcif: process requests asynchronously
From: Guennadi Liakhovetski @ 2011-12-14 18:31 UTC (permalink / raw)
To: linux-mmc; +Cc: linux-sh, Chris Ball, Magnus Damm
In-Reply-To: <Pine.LNX.4.64.1111301553330.22197@axis700.grange>
This used to be a single patch, which now has been split into 2, plus, two more
not directly related patches for the same driver have been included. Patch 1/4
is actually a fix and could be considered for 3.2, but I personally haven't
heard any bug-reports, that could be attributed to it, so, it doesn't seem to
be very critical. Also, on request from Magnus, a state machine description has
been added to the file header.
Guennadi Liakhovetski (4):
mmc: sh_mmcif: process error interrupts first
mmc: sh_mmcif: cosmetic clean up
mmc: sh_mmcif: process requests asynchronously
mmc: sh_mmcif: remove now superfluous sh_mmcif_host::data member
drivers/mmc/host/sh_mmcif.c | 709 +++++++++++++++++++++++++++++--------------
1 files changed, 474 insertions(+), 235 deletions(-)
--
1.7.2.5
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* Re: [PATCH v4 REPOST 3/5] omap4: Unconditionally require l2x0 L2
From: Dave Martin @ 2011-12-14 18:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20111214181425.GB32251@atomide.com>
On Wed, Dec 14, 2011 at 10:14:25AM -0800, Tony Lindgren wrote:
> * Dave Martin <dave.martin@linaro.org> [111214 03:08]:
> > If running in the Normal World on a TrustZone-enabled SoC, Linux
> > does not have complete control over the L2 cache controller
> > configuration. The kernel cannot work reliably on such platforms
> > without the l2x0 cache support code built in.
>
> There are HS and GP omaps (High Security and General Purpose).
> GP omaps do have full control of the L2. Also HS omaps most likely
> provide control over enabling and disabling L2 depending how the
> secure code is implemented.
>
> BTW, the real problem is that because the secure code is implemented
> in various ways, we don't really have any handling for it in Linux.
>
> The SMI instruction numbers don't seem to be standardized at all,
> and can mean different things on different boards, even different
> board versions :(
>
> Sounds like devicetree is the only safe way to deal with the L2
> control options.
>
> Regards,
>
> Tony
>
>
> > This patch unconditionally enables l2x0 support for the OMAP4 SoCs.
> >
> > Thanks to Rob Herring for this suggestion. [1]
> >
> > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> >
> > [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2011-November/074495.html
> > ---
> > arch/arm/mach-omap2/Kconfig | 2 +-
> > 1 files changed, 1 insertions(+), 1 deletions(-)
> >
> > diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
> > index bb1b670..94e568a 100644
> > --- a/arch/arm/mach-omap2/Kconfig
> > +++ b/arch/arm/mach-omap2/Kconfig
> > @@ -41,11 +41,11 @@ config ARCH_OMAP4
> > bool "TI OMAP4"
> > default y
> > depends on ARCH_OMAP2PLUS
> > + select CACHE_L2X0
> > select CPU_V7
> > select ARM_GIC
> > select HAVE_SMP
> > select LOCAL_TIMERS if SMP
> > - select MIGHT_HAVE_CACHE_L2X0
> > select PL310_ERRATA_588369
> > select PL310_ERRATA_727915
> > select ARM_ERRATA_720789
> > --
> > 1.7.4.1
> >
To clarify, are you suggesting we retain this patch, or not?
(If we only know what l2x0 support will be needed once the dts is
parsed at runtime, there could be an argument for keeping the
select CACHE_L2X0 here -- unless we have specific kconfigs for
the different security variants of omap.)
Cheers
---Dave
^ permalink raw reply
* Re: [PATCH v4 REPOST 2/5] ARM: SMP: Refactor Kconfig to be more
From: Tony Lindgren @ 2011-12-14 18:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323862781-3465-3-git-send-email-dave.martin@linaro.org>
* Dave Martin <dave.martin@linaro.org> [111214 03:08]:
> Making SMP depend on (huge list of MACH_ and ARCH_ configs) is
> bothersome to maintain and likely to lead to merge conflicts.
>
> This patch moves the knowledge of which platforms are SMP-capable
> to the individual machines. To enable this, a new HAVE_SMP config
> option is introduced to allow machines to indicate that they can
> run in a SMP configuration.
For omap:
Acked-by: Tony Lindgren <tony@atomide.com>
^ 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