* [PATCH] ARM: futex: fix clobbering oldval
From: Will Deacon @ 2011-09-22 17:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316660015.6872.1.camel@puffmine-laptop>
Hi,
On Thu, Sep 22, 2011 at 03:53:35AM +0100, mhban wrote:
> This patch fixes clobbering oldval bug. oldval should be preserved for next
> compare operation.
>
> Change-Id: I2a63bc1bdb8de330eb9e1ac02d7da1f77e6e8c3c
> Signed-off-by: Minho Ban <mhban@samsung.com>
It would have been nice to have been CC'd on this...
I ran LTP tests on this, so I'm surprised that this was broken (the tests
passed). Well spotted anyway!
> ---
> arch/arm/include/asm/futex.h | 6 +++---
> 1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
> index d2d733c..b0f2e8e 100644
> --- a/arch/arm/include/asm/futex.h
> +++ b/arch/arm/include/asm/futex.h
> @@ -30,14 +30,14 @@
> __asm__ __volatile__( \
> "1: ldrex %1, [%2]\n" \
> " " insn "\n" \
> - "2: strex %1, %0, [%2]\n" \
> - " teq %1, #0\n" \
> + "2: strex r5, %0, [%2]\n" \
> + " teq r5, #0\n" \
> " bne 1b\n" \
> " mov %0, #0\n" \
> __futex_atomic_ex_table("%4") \
> : "=&r" (ret), "=&r" (oldval) \
> : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
> - : "cc", "memory")
> + : "r5", "cc", "memory")
You shouldn't reference r5 directly here, but due to the way the futex code
is laid out, you can't add an extra output operand without converting the
code to use named arguments.
I'll post a patch to do that.
Will
^ permalink raw reply
* [PATCH v3 1/4] ARM: mx53: Change pad configs for flexcan pins
From: Rogerio Pimentel @ 2011-09-22 17:30 UTC (permalink / raw)
To: linux-arm-kernel
Changing pad configs for flexcan on i.MX53
Signed-off-by: Rogerio Pimentel <rogerio.pimentel@freescale.com>
---
Changes since v2:
Rebased to imx-cleanup, changed the patch subject
arch/arm/plat-mxc/include/mach/iomux-mx53.h | 23 ++++++++++++-----------
1 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx53.h b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
index 527f8fe..12b5a5d 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx53.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
@@ -30,7 +30,8 @@
#define MX53_SDHC_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_HIGH | \
PAD_CTL_SRE_FAST)
-
+#define MX53_CAN_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_DSE_HIGH | \
+ PAD_CTL_HYS)
#define MX53_PAD_GPIO_19__KPP_COL_5 IOMUX_PAD(0x348, 0x020, 0, 0x840, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_19__GPIO4_5 IOMUX_PAD(0x348, 0x020, 1, __NA_, 0, NO_PAD_CTRL)
@@ -69,14 +70,14 @@
#define MX53_PAD_KEY_ROW1__USBPHY1_RXVALID IOMUX_PAD(0x358, 0x030, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL2__KPP_COL_2 IOMUX_PAD(0x35C, 0x034, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL2__GPIO4_10 IOMUX_PAD(0x35C, 0x034, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL2__CAN1_TXCAN IOMUX_PAD(0x35C, 0x034, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX53_PAD_KEY_COL2__CAN1_TXCAN IOMUX_PAD(0x35C, 0x034, 2, __NA_, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_KEY_COL2__FEC_MDIO IOMUX_PAD(0x35C, 0x034, 4, 0x804, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL2__ECSPI1_SS1 IOMUX_PAD(0x35C, 0x034, 5, 0x7AC, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL2__FEC_RDATA_2 IOMUX_PAD(0x35C, 0x034, 6, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL2__USBPHY1_RXACTIVE IOMUX_PAD(0x35C, 0x034, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW2__KPP_ROW_2 IOMUX_PAD(0x360, 0x038, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW2__GPIO4_11 IOMUX_PAD(0x360, 0x038, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW2__CAN1_RXCAN IOMUX_PAD(0x360, 0x038, 2, 0x760, 0, NO_PAD_CTRL)
+#define MX53_PAD_KEY_ROW2__CAN1_RXCAN IOMUX_PAD(0x360, 0x038, 2, 0x760, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_KEY_ROW2__FEC_MDC IOMUX_PAD(0x360, 0x038, 4, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW2__ECSPI1_SS2 IOMUX_PAD(0x360, 0x038, 5, 0x7B0, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW2__FEC_TDATA_2 IOMUX_PAD(0x360, 0x038, 6, __NA_, 0, NO_PAD_CTRL)
@@ -99,14 +100,14 @@
#define MX53_PAD_KEY_ROW3__USBPHY1_LINESTATE_0 IOMUX_PAD(0x368, 0x040, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL4__KPP_COL_4 IOMUX_PAD(0x36C, 0x044, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL4__GPIO4_14 IOMUX_PAD(0x36C, 0x044, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_COL4__CAN2_TXCAN IOMUX_PAD(0x36C, 0x044, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX53_PAD_KEY_COL4__CAN2_TXCAN IOMUX_PAD(0x36C, 0x044, 2, __NA_, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_KEY_COL4__IPU_SISG_4 IOMUX_PAD(0x36C, 0x044, 3, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL4__UART5_RTS IOMUX_PAD(0x36C, 0x044, 4, 0x894, 0, MX53_UART_PAD_CTRL)
#define MX53_PAD_KEY_COL4__USBOH3_USBOTG_OC IOMUX_PAD(0x36C, 0x044, 5, 0x89C, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_COL4__USBPHY1_LINESTATE_1 IOMUX_PAD(0x36C, 0x044, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW4__KPP_ROW_4 IOMUX_PAD(0x370, 0x048, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW4__GPIO4_15 IOMUX_PAD(0x370, 0x048, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_KEY_ROW4__CAN2_RXCAN IOMUX_PAD(0x370, 0x048, 2, 0x764, 0, NO_PAD_CTRL)
+#define MX53_PAD_KEY_ROW4__CAN2_RXCAN IOMUX_PAD(0x370, 0x048, 2, 0x764, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_KEY_ROW4__IPU_SISG_5 IOMUX_PAD(0x370, 0x048, 3, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_KEY_ROW4__UART5_CTS IOMUX_PAD(0x370, 0x048, 4, __NA_, 0, MX53_UART_PAD_CTRL)
#define MX53_PAD_KEY_ROW4__USBOH3_USBOTG_PWR IOMUX_PAD(0x370, 0x048, 5, __NA_, 0, NO_PAD_CTRL)
@@ -891,25 +892,25 @@
#define MX53_PAD_PATA_INTRQ__PATA_INTRQ IOMUX_PAD(0x600, 0x280, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_INTRQ__GPIO7_2 IOMUX_PAD(0x600, 0x280, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_INTRQ__UART2_CTS IOMUX_PAD(0x600, 0x280, 3, __NA_, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_PATA_INTRQ__CAN1_TXCAN IOMUX_PAD(0x600, 0x280, 4, __NA_, 0, NO_PAD_CTRL)
+#define MX53_PAD_PATA_INTRQ__CAN1_TXCAN IOMUX_PAD(0x600, 0x280, 4, __NA_, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_PATA_INTRQ__CCM_CCM_OUT_2 IOMUX_PAD(0x600, 0x280, 5, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_INTRQ__USBPHY2_DATAOUT_6 IOMUX_PAD(0x600, 0x280, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_DIOR__PATA_DIOR IOMUX_PAD(0x604, 0x284, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_DIOR__GPIO7_3 IOMUX_PAD(0x604, 0x284, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_DIOR__UART2_RTS IOMUX_PAD(0x604, 0x284, 3, 0x87C, 3, MX53_UART_PAD_CTRL)
-#define MX53_PAD_PATA_DIOR__CAN1_RXCAN IOMUX_PAD(0x604, 0x284, 4, 0x760, 1, NO_PAD_CTRL)
+#define MX53_PAD_PATA_DIOR__CAN1_RXCAN IOMUX_PAD(0x604, 0x284, 4, 0x760, 1, MX53_CAN_PAD_CTRL)
#define MX53_PAD_PATA_DIOR__USBPHY2_DATAOUT_7 IOMUX_PAD(0x604, 0x284, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_RESET_B__PATA_PATA_RESET_B IOMUX_PAD(0x608, 0x288, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_RESET_B__GPIO7_4 IOMUX_PAD(0x608, 0x288, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_RESET_B__ESDHC3_CMD IOMUX_PAD(0x608, 0x288, 2, __NA_, 0, MX53_SDHC_PAD_CTRL)
#define MX53_PAD_PATA_RESET_B__UART1_CTS IOMUX_PAD(0x608, 0x288, 3, __NA_, 0, MX53_UART_PAD_CTRL)
-#define MX53_PAD_PATA_RESET_B__CAN2_TXCAN IOMUX_PAD(0x608, 0x288, 4, __NA_, 0, NO_PAD_CTRL)
+#define MX53_PAD_PATA_RESET_B__CAN2_TXCAN IOMUX_PAD(0x608, 0x288, 4, __NA_, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_PATA_RESET_B__USBPHY1_DATAOUT_0 IOMUX_PAD(0x608, 0x288, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_IORDY__PATA_IORDY IOMUX_PAD(0x60C, 0x28C, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_IORDY__GPIO7_5 IOMUX_PAD(0x60C, 0x28C, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_IORDY__ESDHC3_CLK IOMUX_PAD(0x60C, 0x28C, 2, __NA_, 0, MX53_SDHC_PAD_CTRL)
#define MX53_PAD_PATA_IORDY__UART1_RTS IOMUX_PAD(0x60C, 0x28C, 3, 0x874, 3, MX53_UART_PAD_CTRL)
-#define MX53_PAD_PATA_IORDY__CAN2_RXCAN IOMUX_PAD(0x60C, 0x28C, 4, 0x764, 1, NO_PAD_CTRL)
+#define MX53_PAD_PATA_IORDY__CAN2_RXCAN IOMUX_PAD(0x60C, 0x28C, 4, 0x764, 1, MX53_CAN_PAD_CTRL)
#define MX53_PAD_PATA_IORDY__USBPHY1_DATAOUT_1 IOMUX_PAD(0x60C, 0x28C, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_DA_0__PATA_DA_0 IOMUX_PAD(0x610, 0x290, 0, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_PATA_DA_0__GPIO7_6 IOMUX_PAD(0x610, 0x290, 1, __NA_, 0, NO_PAD_CTRL)
@@ -1179,7 +1180,7 @@
#define MX53_PAD_GPIO_7__ESAI1_TX4_RX1 IOMUX_PAD(0x6C4, 0x334, 0, 0x7F4, 1, NO_PAD_CTRL)
#define MX53_PAD_GPIO_7__GPIO1_7 IOMUX_PAD(0x6C4, 0x334, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_7__EPIT1_EPITO IOMUX_PAD(0x6C4, 0x334, 2, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_7__CAN1_TXCAN IOMUX_PAD(0x6C4, 0x334, 3, __NA_, 0, NO_PAD_CTRL)
+#define MX53_PAD_GPIO_7__CAN1_TXCAN IOMUX_PAD(0x6C4, 0x334, 3, __NA_, 0, MX53_CAN_PAD_CTRL)
#define MX53_PAD_GPIO_7__UART2_TXD_MUX IOMUX_PAD(0x6C4, 0x334, 4, __NA_, 0, MX53_UART_PAD_CTRL)
#define MX53_PAD_GPIO_7__FIRI_RXD IOMUX_PAD(0x6C4, 0x334, 5, 0x80C, 1, NO_PAD_CTRL)
#define MX53_PAD_GPIO_7__SPDIF_PLOCK IOMUX_PAD(0x6C4, 0x334, 6, __NA_, 0, NO_PAD_CTRL)
@@ -1187,7 +1188,7 @@
#define MX53_PAD_GPIO_8__ESAI1_TX5_RX0 IOMUX_PAD(0x6C8, 0x338, 0, 0x7F8, 1, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__GPIO1_8 IOMUX_PAD(0x6C8, 0x338, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__EPIT2_EPITO IOMUX_PAD(0x6C8, 0x338, 2, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_8__CAN1_RXCAN IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 3, NO_PAD_CTRL)
+#define MX53_PAD_GPIO_8__CAN1_RXCAN IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 3, MX53_CAN_PAD_CTRL)
#define MX53_PAD_GPIO_8__UART2_RXD_MUX IOMUX_PAD(0x6C8, 0x338, 4, 0x880, 5, MX53_UART_PAD_CTRL)
#define MX53_PAD_GPIO_8__FIRI_TXD IOMUX_PAD(0x6C8, 0x338, 5, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__SPDIF_SRCLK IOMUX_PAD(0x6C8, 0x338, 6, __NA_, 0, NO_PAD_CTRL)
--
1.7.1
^ permalink raw reply related
* [PATCH v3 2/4] ARM: mx53: Add clock for flexcan
From: Rogerio Pimentel @ 2011-09-22 17:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316712635-25126-1-git-send-email-rogerio.pimentel@freescale.com>
Adding clock for flexcan on i.MX53
Signed-off-by: Rogerio Pimentel <rogerio.pimentel@freescale.com>
---
Changes since v2:
Rebased to imx-cleanup
arch/arm/mach-mx5/clock-mx51-mx53.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index a3db355..30d008f 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -1418,6 +1418,12 @@ DEFINE_CLOCK(ipu_di0_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG5_OFFSET,
DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET,
NULL, NULL, &pll3_sw_clk, NULL);
+/* CAN */
+DEFINE_CLOCK(can1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG10_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(can2_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG3_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+
#define _REGISTER_CLOCK(d, n, c) \
{ \
.dev_id = d, \
@@ -1507,6 +1513,8 @@ static struct clk_lookup mx53_lookups[] = {
_REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
_REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk)
_REGISTER_CLOCK("imx-keypad", NULL, dummy_clk)
+ _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
+ _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
};
static void clk_tree_init(void)
--
1.7.1
^ permalink raw reply related
* [PATCH v3 3/4] ARM: mx53: Add resources for flexcan
From: Rogerio Pimentel @ 2011-09-22 17:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316712635-25126-1-git-send-email-rogerio.pimentel@freescale.com>
Adding resources for flexcan on i.MX53
Signed-off-by: Rogerio Pimentel <rogerio.pimentel@freescale.com>
---
Changes since v2:
Rebased to imx-cleanup
arch/arm/mach-mx5/devices-imx53.h | 6 ++++++
arch/arm/plat-mxc/devices/platform-flexcan.c | 7 +++++++
arch/arm/plat-mxc/include/mach/mx53.h | 2 ++
3 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index c27fe8b..a3e1375 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -40,3 +40,9 @@ extern const struct imx_imx_ssi_data imx53_imx_ssi_data[];
extern const struct imx_imx_keypad_data imx53_imx_keypad_data;
#define imx53_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx53_imx_keypad_data, pdata)
+
+extern const struct imx_flexcan_data imx53_flexcan_data[];
+#define imx53_add_flexcan(id, pdata) \
+ imx_add_flexcan(&imx53_flexcan_data[id], pdata)
+#define imx53_add_flexcan0(pdata) imx53_add_flexcan(0, pdata)
+#define imx53_add_flexcan1(pdata) imx53_add_flexcan(1, pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-flexcan.c b/arch/arm/plat-mxc/devices/platform-flexcan.c
index 4e8497a..4cce16b 100644
--- a/arch/arm/plat-mxc/devices/platform-flexcan.c
+++ b/arch/arm/plat-mxc/devices/platform-flexcan.c
@@ -37,6 +37,13 @@ const struct imx_flexcan_data imx35_flexcan_data[] __initconst = {
};
#endif /* ifdef CONFIG_SOC_IMX35 */
+#ifdef CONFIG_SOC_IMX53
+const struct imx_flexcan_data imx53_flexcan_data[] __initconst = {
+ imx_flexcan_data_entry(MX53, 0, 1, SZ_16K),
+ imx_flexcan_data_entry(MX53, 1, 2, SZ_16K),
+};
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
struct platform_device *__init imx_add_flexcan(
const struct imx_flexcan_data *data,
const struct flexcan_platform_data *pdata)
diff --git a/arch/arm/plat-mxc/include/mach/mx53.h b/arch/arm/plat-mxc/include/mach/mx53.h
index a37e8c3..13cb2a5 100644
--- a/arch/arm/plat-mxc/include/mach/mx53.h
+++ b/arch/arm/plat-mxc/include/mach/mx53.h
@@ -91,6 +91,8 @@
#define MX53_PWM2_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000B8000)
#define MX53_UART1_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000BC000)
#define MX53_UART2_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000C0000)
+#define MX53_CAN1_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000C8000)
+#define MX53_CAN2_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000CC000)
#define MX53_SRC_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000D0000)
#define MX53_CCM_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000D4000)
#define MX53_GPC_BASE_ADDR (MX53_AIPS1_BASE_ADDR + 0x000D8000)
--
1.7.1
^ permalink raw reply related
* [PATCH v3 4/4] ARM: mx53_ard: Add flexcan support
From: Rogerio Pimentel @ 2011-09-22 17:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316712635-25126-1-git-send-email-rogerio.pimentel@freescale.com>
Adding flexcan support on i.MX53 ARD
Signed-off-by: Rogerio Pimentel <rogerio.pimentel@freescale.com>
---
Changes since v2:
Rebased to imx-cleanup, using gpio_request_array
instead gpio_request_one
arch/arm/mach-mx5/Kconfig | 1 +
arch/arm/mach-mx5/board-mx53_ard.c | 39 ++++++++++++++++++++++++++++++-----
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index b4f5ab6..c71731e 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -218,6 +218,7 @@ config MACH_MX53_LOCO
config MACH_MX53_ARD
bool "Support MX53 ARD platforms"
select SOC_IMX53
+ select IMX_HAVE_PLATFORM_FLEXCAN
select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
diff --git a/arch/arm/mach-mx5/board-mx53_ard.c b/arch/arm/mach-mx5/board-mx53_ard.c
index ddc3015..e29bb23 100644
--- a/arch/arm/mach-mx5/board-mx53_ard.c
+++ b/arch/arm/mach-mx5/board-mx53_ard.c
@@ -44,6 +44,8 @@
#define ARD_BACK IMX_GPIO_NR(5, 11)
#define ARD_PROG IMX_GPIO_NR(5, 12)
#define ARD_VOLUMEUP IMX_GPIO_NR(5, 13)
+#define ARD_CAN_EN IMX_GPIO_NR(7, 6)
+#define ARD_CAN_STBY IMX_GPIO_NR(4, 15)
static iomux_v3_cfg_t mx53_ard_pads[] = {
/* UART1 */
@@ -102,6 +104,13 @@ static iomux_v3_cfg_t mx53_ard_pads[] = {
MX53_PAD_DISP0_DAT18__GPIO5_12, /* prog */
MX53_PAD_DISP0_DAT19__GPIO5_13, /* vol up */
MX53_PAD_GPIO_10__GPIO4_0, /* vol down */
+ /* CAN */
+ MX53_PAD_KEY_COL2__CAN1_TXCAN | PAD_CTL_PUS_100K_UP,
+ MX53_PAD_KEY_ROW2__CAN1_RXCAN,
+ MX53_PAD_PATA_RESET_B__CAN2_TXCAN | PAD_CTL_PUS_100K_UP,
+ MX53_PAD_PATA_IORDY__CAN2_RXCAN,
+ MX53_PAD_PATA_DA_0__GPIO7_6,
+ MX53_PAD_KEY_ROW4__GPIO4_15,
};
#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \
@@ -169,16 +178,27 @@ static struct imxi2c_platform_data mx53_ard_i2c3_data = {
.bitrate = 400000,
};
-static void __init mx53_ard_io_init(void)
+static struct gpio mx53_ard_gpios[] = {
+ { ARD_ETHERNET_INT_B, GPIOF_IN, "eth-int-b" },
+ { ARD_I2CPORTEXP_B, GPIOF_OUT_INIT_HIGH, "i2cptexp-rst" },
+ { ARD_CAN_EN, GPIOF_OUT_INIT_HIGH, "can-en" },
+ { ARD_CAN_STBY, GPIOF_OUT_INIT_HIGH, "can-stby" },
+};
+
+static int __init mx53_ard_io_init(void)
{
+ int ret;
+
mxc_iomux_v3_setup_multiple_pads(mx53_ard_pads,
ARRAY_SIZE(mx53_ard_pads));
- gpio_request(ARD_ETHERNET_INT_B, "eth-int-b");
- gpio_direction_input(ARD_ETHERNET_INT_B);
+ ret = gpio_request_array(mx53_ard_gpios,
+ ARRAY_SIZE(mx53_ard_gpios));
+
+ if (ret)
+ return ret;
- gpio_request(ARD_I2CPORTEXP_B, "i2cptexp-rst");
- gpio_direction_output(ARD_I2CPORTEXP_B, 1);
+ return 0;
}
/* Config CS1 settings for ethernet controller */
@@ -222,10 +242,15 @@ static struct platform_device *devices[] __initdata = {
static void __init mx53_ard_board_init(void)
{
+ int ret;
+
imx53_soc_init();
imx53_add_imx_uart(0, NULL);
- mx53_ard_io_init();
+ ret = mx53_ard_io_init();
+ if (ret)
+ pr_err("failed to request gpio pins: %d\n", ret);
+
weim_cs_config();
platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -234,6 +259,8 @@ static void __init mx53_ard_board_init(void)
imx53_add_imx_i2c(1, &mx53_ard_i2c2_data);
imx53_add_imx_i2c(2, &mx53_ard_i2c3_data);
imx_add_gpio_keys(&ard_button_data);
+ imx53_add_flexcan0(NULL);
+ imx53_add_flexcan1(NULL);
}
static void __init mx53_ard_timer_init(void)
--
1.7.1
^ permalink raw reply related
* [PATCH v3 1/2] input: samsung-keypad: Add HAVE_SAMSUNG_KEYPAD config option
From: Grant Likely @ 2011-09-22 17:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316427553-5033-2-git-send-email-thomas.abraham@linaro.org>
On Mon, Sep 19, 2011 at 03:49:12PM +0530, Thomas Abraham wrote:
> For platforms using device tree, the static keypad device instances
> are not required and SAMSUNG_DEV_KEYPAD is not selected. Since,
> samsung keypad driver has dependency on SAMSUNG_DEV_KEYPAD config
> option, the driver is left out of the compilation for dt enabled
> platforms.
>
> An additional config option 'HAVE_SAMSUNG_KEYPAD' is added
> which the device tree based platforms can select. This config
> option is added as an alternative dependency for keypad driver.
>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> ---
> drivers/input/keyboard/Kconfig | 9 ++++++++-
> 1 files changed, 8 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index b4dee9d..7c322a3 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -423,9 +423,16 @@ config KEYBOARD_PMIC8XXX
> To compile this driver as a module, choose M here: the module will
> be called pmic8xxx-keypad.
>
> +config HAVE_SAMSUNG_KEYPAD
> + bool
> + help
> + This will include Samsung Keypad controller driver support. If you
> + want to include Samsung Keypad support for any machine, kindly
> + select this in the respective mach-xxxx/Kconfig file.
> +
> config KEYBOARD_SAMSUNG
> tristate "Samsung keypad support"
> - depends on SAMSUNG_DEV_KEYPAD
> + depends on SAMSUNG_DEV_KEYPAD || HAVE_SAMSUNG_KEYPAD
It would be better to modify SAMSUNG_DEV_KEYPAD to select
HAVE_SAMSUNG_KEYPAD and then make KEYBOARD_SAMSUNG only depend on
HAVE_SAMSUNG_KEYPAD instead of both.
g.
^ permalink raw reply
* [RFC PATCH V6 0/4] cpuidle: Global registration of idle states with per-cpu statistics
From: Arjan van de Ven @ 2011-09-22 17:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922082840.10520.85895.stgit@localhost6.localdomain6>
On 9/22/2011 1:28 AM, Deepthi Dharwar wrote:
> The following patch series implements global registration of cpuidle
> states, and also has the necessary data structure changes to
> accommodate the per-cpu writable members of the cpuidle_states
> structure.
>
you can consider this series Acked-by: Arjan van de Ven
<arjan@linux.intel.com>
it's a good simplification of the code, and unlike frequencies, idle
states are really shared between all cpus for
very practical reasons.
^ permalink raw reply
* [PATCH] ARM: platform fixups: remove mdesc argument to fixup function
From: Nicolas Pitre @ 2011-09-22 17:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1R6kA4-0002vc-HZ@rmk-PC.arm.linux.org.uk>
On Thu, 22 Sep 2011, Russell King - ARM Linux wrote:
> Get rid of the mdesc pointer in the fixup function call. No one uses
> the mdesc pointer, it shouldn't be modified anyway, and we can't wrap
> it, so let's remove it. Updated for 3.1-rc6.
>
> Platform files found by:
>
> $ regexp=$(git grep -h '\.fixup.*=' arch/arm |
> sed 's!.*= *\([^,]*\),* *!\1!' | sort -u |
> tr '\n' '|' | sed 's,|$,,;s,|,\\|,g')
> $ git grep $regexp arch/arm
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> ---
> arch/arm/include/asm/mach/arch.h | 3 +--
> arch/arm/kernel/setup.c | 2 +-
> arch/arm/mach-bcmring/arch.c | 4 ++--
> arch/arm/mach-clps711x/clep7312.c | 3 +--
> arch/arm/mach-clps711x/edb7211-arch.c | 3 +--
> arch/arm/mach-clps711x/fortunet.c | 3 +--
> arch/arm/mach-clps711x/p720t.c | 3 +--
> arch/arm/mach-footbridge/cats-hw.c | 3 +--
> arch/arm/mach-footbridge/netwinder-hw.c | 3 +--
> arch/arm/mach-msm/board-halibut.c | 4 ++--
> arch/arm/mach-msm/board-mahimahi.c | 4 ++--
> arch/arm/mach-msm/board-sapphire.c | 4 ++--
> arch/arm/mach-msm/board-trout.c | 4 ++--
> arch/arm/mach-orion5x/common.c | 4 ++--
> arch/arm/mach-orion5x/common.h | 4 +---
> arch/arm/mach-pxa/cm-x300.c | 4 ++--
> arch/arm/mach-pxa/corgi.c | 4 ++--
> arch/arm/mach-pxa/eseries.c | 3 +--
> arch/arm/mach-pxa/eseries.h | 3 +--
> arch/arm/mach-pxa/poodle.c | 4 ++--
> arch/arm/mach-pxa/spitz.c | 4 ++--
> arch/arm/mach-pxa/tosa.c | 4 ++--
> arch/arm/mach-realview/core.c | 3 +--
> arch/arm/mach-realview/core.h | 4 ++--
> arch/arm/mach-realview/realview_pb1176.c | 3 +--
> arch/arm/mach-realview/realview_pbx.c | 6 +++---
> arch/arm/mach-s3c2412/mach-smdk2413.c | 3 +--
> arch/arm/mach-s3c2412/mach-vstms.c | 5 ++---
> arch/arm/mach-sa1100/assabet.c | 3 +--
> arch/arm/mach-tegra/board-harmony.c | 4 ++--
> arch/arm/mach-tegra/board-paz00.c | 4 ++--
> arch/arm/mach-tegra/board-trimslice.c | 4 ++--
> 32 files changed, 50 insertions(+), 66 deletions(-)
>
> diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
> index 217aa19..c569998 100644
> --- a/arch/arm/include/asm/mach/arch.h
> +++ b/arch/arm/include/asm/mach/arch.h
> @@ -34,8 +34,7 @@ struct machine_desc {
> unsigned int reserve_lp1 :1; /* never has lp1 */
> unsigned int reserve_lp2 :1; /* never has lp2 */
> unsigned int soft_reboot :1; /* soft reboot */
> - void (*fixup)(struct machine_desc *,
> - struct tag *, char **,
> + void (*fixup)(struct tag *, char **,
> struct meminfo *);
> void (*reserve)(void);/* reserve mem blocks */
> void (*map_io)(void);/* IO mapping function */
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index e514c76..f10fed0 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -861,7 +861,7 @@ static struct machine_desc * __init setup_machine_tags(unsigned int nr)
> }
>
> if (mdesc->fixup)
> - mdesc->fixup(mdesc, tags, &from, &meminfo);
> + mdesc->fixup(tags, &from, &meminfo);
>
> if (tags->hdr.tag == ATAG_CORE) {
> if (meminfo.nr_banks != 0)
> diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
> index a604b9e..31a1435 100644
> --- a/arch/arm/mach-bcmring/arch.c
> +++ b/arch/arm/mach-bcmring/arch.c
> @@ -136,8 +136,8 @@ static void __init bcmring_init_machine(void)
> *
> *****************************************************************************/
>
> -static void __init bcmring_fixup(struct machine_desc *desc,
> - struct tag *t, char **cmdline, struct meminfo *mi) {
> +static void __init bcmring_fixup(struct tag *t, char **cmdline,
> + struct meminfo *mi) {
> #ifdef CONFIG_BLK_DEV_INITRD
> printk(KERN_NOTICE "bcmring_fixup\n");
> t->hdr.tag = ATAG_CORE;
> diff --git a/arch/arm/mach-clps711x/clep7312.c b/arch/arm/mach-clps711x/clep7312.c
> index 67b5abb4..0a2e74f 100644
> --- a/arch/arm/mach-clps711x/clep7312.c
> +++ b/arch/arm/mach-clps711x/clep7312.c
> @@ -26,8 +26,7 @@
> #include "common.h"
>
> static void __init
> -fixup_clep7312(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fixup_clep7312(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> mi->nr_banks=1;
> mi->bank[0].start = 0xc0000000;
> diff --git a/arch/arm/mach-clps711x/edb7211-arch.c b/arch/arm/mach-clps711x/edb7211-arch.c
> index 98ca5b2..725a7a5 100644
> --- a/arch/arm/mach-clps711x/edb7211-arch.c
> +++ b/arch/arm/mach-clps711x/edb7211-arch.c
> @@ -37,8 +37,7 @@ static void __init edb7211_reserve(void)
> }
>
> static void __init
> -fixup_edb7211(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fixup_edb7211(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> /*
> * Bank start addresses are not present in the information
> diff --git a/arch/arm/mach-clps711x/fortunet.c b/arch/arm/mach-clps711x/fortunet.c
> index b1cb479..1947b30 100644
> --- a/arch/arm/mach-clps711x/fortunet.c
> +++ b/arch/arm/mach-clps711x/fortunet.c
> @@ -57,8 +57,7 @@ typedef struct tag_IMAGE_PARAMS
> #define IMAGE_PARAMS_PHYS 0xC01F0000
>
> static void __init
> -fortunet_fixup(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fortunet_fixup(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> IMAGE_PARAMS *ip = phys_to_virt(IMAGE_PARAMS_PHYS);
> *cmdline = phys_to_virt(ip->command_line);
> diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
> index cefbce0..3f796e0 100644
> --- a/arch/arm/mach-clps711x/p720t.c
> +++ b/arch/arm/mach-clps711x/p720t.c
> @@ -56,8 +56,7 @@ static struct map_desc p720t_io_desc[] __initdata = {
> };
>
> static void __init
> -fixup_p720t(struct machine_desc *desc, struct tag *tag,
> - char **cmdline, struct meminfo *mi)
> +fixup_p720t(struct tag *tag, char **cmdline, struct meminfo *mi)
> {
> /*
> * Our bootloader doesn't setup any tags (yet).
> diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
> index 5b1a8db..206ff2f 100644
> --- a/arch/arm/mach-footbridge/cats-hw.c
> +++ b/arch/arm/mach-footbridge/cats-hw.c
> @@ -76,8 +76,7 @@ __initcall(cats_hw_init);
> * hard reboots fail on early boards.
> */
> static void __init
> -fixup_cats(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fixup_cats(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> screen_info.orig_video_lines = 25;
> screen_info.orig_video_points = 16;
> diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
> index 06e514f..4cbc2e6 100644
> --- a/arch/arm/mach-footbridge/netwinder-hw.c
> +++ b/arch/arm/mach-footbridge/netwinder-hw.c
> @@ -631,8 +631,7 @@ __initcall(nw_hw_init);
> * the parameter page.
> */
> static void __init
> -fixup_netwinder(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fixup_netwinder(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> #ifdef CONFIG_ISAPNP
> extern int isapnp_disable;
> diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c
> index 18a3c97..f81ef1f 100644
> --- a/arch/arm/mach-msm/board-halibut.c
> +++ b/arch/arm/mach-msm/board-halibut.c
> @@ -78,8 +78,8 @@ static void __init halibut_init(void)
> platform_add_devices(devices, ARRAY_SIZE(devices));
> }
>
> -static void __init halibut_fixup(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +static void __init halibut_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks=1;
> mi->bank[0].start = PHYS_OFFSET;
> diff --git a/arch/arm/mach-msm/board-mahimahi.c b/arch/arm/mach-msm/board-mahimahi.c
> index 7a9a03e..1df15aa 100644
> --- a/arch/arm/mach-msm/board-mahimahi.c
> +++ b/arch/arm/mach-msm/board-mahimahi.c
> @@ -53,8 +53,8 @@ static void __init mahimahi_init(void)
> platform_add_devices(devices, ARRAY_SIZE(devices));
> }
>
> -static void __init mahimahi_fixup(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +static void __init mahimahi_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks = 2;
> mi->bank[0].start = PHYS_OFFSET;
> diff --git a/arch/arm/mach-msm/board-sapphire.c b/arch/arm/mach-msm/board-sapphire.c
> index 68f930f..c6e043c 100644
> --- a/arch/arm/mach-msm/board-sapphire.c
> +++ b/arch/arm/mach-msm/board-sapphire.c
> @@ -77,8 +77,8 @@ static struct map_desc sapphire_io_desc[] __initdata = {
> }
> };
>
> -static void __init sapphire_fixup(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +static void __init sapphire_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> int smi_sz = parse_tag_smi((const struct tag *)tags);
>
> diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
> index 8143867..7acd202 100644
> --- a/arch/arm/mach-msm/board-trout.c
> +++ b/arch/arm/mach-msm/board-trout.c
> @@ -48,8 +48,8 @@ static void __init trout_init_irq(void)
> msm_init_irq();
> }
>
> -static void __init trout_fixup(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +static void __init trout_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks = 1;
> mi->bank[0].start = PHYS_OFFSET;
> diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
> index 0ab531d..22ace0b 100644
> --- a/arch/arm/mach-orion5x/common.c
> +++ b/arch/arm/mach-orion5x/common.c
> @@ -308,8 +308,8 @@ void __init orion5x_init(void)
> * Many orion-based systems have buggy bootloader implementations.
> * This is a common fixup for bogus memory tags.
> */
> -void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t,
> - char **from, struct meminfo *meminfo)
> +void __init tag_fixup_mem32(struct tag *t, char **from,
> + struct meminfo *meminfo)
> {
> for (; t->hdr.size; t = tag_next(t))
> if (t->hdr.tag == ATAG_MEM &&
> diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
> index 3e5499d..909489f 100644
> --- a/arch/arm/mach-orion5x/common.h
> +++ b/arch/arm/mach-orion5x/common.h
> @@ -53,11 +53,9 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
> struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
> int orion5x_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
>
> -struct machine_desc;
> struct meminfo;
> struct tag;
> -extern void __init tag_fixup_mem32(struct machine_desc *, struct tag *,
> - char **, struct meminfo *);
> +extern void __init tag_fixup_mem32(struct tag *, char **, struct meminfo *);
>
>
> #endif
> diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
> index b6a5134..d940e8a 100644
> --- a/arch/arm/mach-pxa/cm-x300.c
> +++ b/arch/arm/mach-pxa/cm-x300.c
> @@ -839,8 +839,8 @@ static void __init cm_x300_init(void)
> cm_x300_init_bl();
> }
>
> -static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +static void __init cm_x300_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> /* Make sure that mi->bank[0].start = PHYS_ADDR */
> for (; tags->hdr.size; tags = tag_next(tags))
> diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
> index 185a37c..3e9483b 100644
> --- a/arch/arm/mach-pxa/corgi.c
> +++ b/arch/arm/mach-pxa/corgi.c
> @@ -705,8 +705,8 @@ static void __init corgi_init(void)
> platform_add_devices(devices, ARRAY_SIZE(devices));
> }
>
> -static void __init fixup_corgi(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init fixup_corgi(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> sharpsl_save_param();
> mi->nr_banks=1;
> diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c
> index b4599ec..e4a1f4d 100644
> --- a/arch/arm/mach-pxa/eseries.c
> +++ b/arch/arm/mach-pxa/eseries.c
> @@ -41,8 +41,7 @@
> #include "clock.h"
>
> /* Only e800 has 128MB RAM */
> -void __init eseries_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> mi->nr_banks=1;
> mi->bank[0].start = 0xa0000000;
> diff --git a/arch/arm/mach-pxa/eseries.h b/arch/arm/mach-pxa/eseries.h
> index 5930f5e..be92196 100644
> --- a/arch/arm/mach-pxa/eseries.h
> +++ b/arch/arm/mach-pxa/eseries.h
> @@ -1,5 +1,4 @@
> -void __init eseries_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi);
> +void __init eseries_fixup(struct tag *tags, char **cmdline, struct meminfo *mi);
>
> extern struct pxa2xx_udc_mach_info e7xx_udc_mach_info;
> extern struct pxaficp_platform_data e7xx_ficp_platform_data;
> diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
> index a113ea9..948ce3e 100644
> --- a/arch/arm/mach-pxa/poodle.c
> +++ b/arch/arm/mach-pxa/poodle.c
> @@ -454,8 +454,8 @@ static void __init poodle_init(void)
> poodle_init_spi();
> }
>
> -static void __init fixup_poodle(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init fixup_poodle(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> sharpsl_save_param();
> mi->nr_banks=1;
> diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
> index 438c7b5..d8dec91 100644
> --- a/arch/arm/mach-pxa/spitz.c
> +++ b/arch/arm/mach-pxa/spitz.c
> @@ -970,8 +970,8 @@ static void __init spitz_init(void)
> spitz_i2c_init();
> }
>
> -static void __init spitz_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init spitz_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> sharpsl_save_param();
> mi->nr_banks = 1;
> diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
> index 9f69a26..402b0c9 100644
> --- a/arch/arm/mach-pxa/tosa.c
> +++ b/arch/arm/mach-pxa/tosa.c
> @@ -960,8 +960,8 @@ static void __init tosa_init(void)
> platform_add_devices(devices, ARRAY_SIZE(devices));
> }
>
> -static void __init fixup_tosa(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init fixup_tosa(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> sharpsl_save_param();
> mi->nr_banks=1;
> diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
> index 5c23450..d5ed5d4 100644
> --- a/arch/arm/mach-realview/core.c
> +++ b/arch/arm/mach-realview/core.c
> @@ -517,8 +517,7 @@ void __init realview_timer_init(unsigned int timer_irq)
> /*
> * Setup the memory banks.
> */
> -void realview_fixup(struct machine_desc *mdesc, struct tag *tags, char **from,
> - struct meminfo *meminfo)
> +void realview_fixup(struct tag *tags, char **from, struct meminfo *meminfo)
> {
> /*
> * Most RealView platforms have 512MB contiguous RAM at 0x70000000.
> diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
> index 5c83d1e..47259c8 100644
> --- a/arch/arm/mach-realview/core.h
> +++ b/arch/arm/mach-realview/core.h
> @@ -63,8 +63,8 @@ extern int realview_flash_register(struct resource *res, u32 num);
> extern int realview_eth_register(const char *name, struct resource *res);
> extern int realview_usb_register(struct resource *res);
> extern void realview_init_early(void);
> -extern void realview_fixup(struct machine_desc *mdesc, struct tag *tags,
> - char **from, struct meminfo *meminfo);
> +extern void realview_fixup(struct tag *tags, char **from,
> + struct meminfo *meminfo);
> extern void (*realview_reset)(char);
>
> #endif
> diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
> index ad5671a..de6b9fa 100644
> --- a/arch/arm/mach-realview/realview_pb1176.c
> +++ b/arch/arm/mach-realview/realview_pb1176.c
> @@ -316,8 +316,7 @@ static void realview_pb1176_reset(char mode)
> __raw_writel(REALVIEW_PB1176_SYS_SOFT_RESET, reset_ctrl);
> }
>
> -static void realview_pb1176_fixup(struct machine_desc *mdesc,
> - struct tag *tags, char **from,
> +static void realview_pb1176_fixup(struct tag *tags, char **from,
> struct meminfo *meminfo)
> {
> /*
> diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
> index 363b0ab..3e1eb2e 100644
> --- a/arch/arm/mach-realview/realview_pbx.c
> +++ b/arch/arm/mach-realview/realview_pbx.c
> @@ -319,8 +319,8 @@ static struct sys_timer realview_pbx_timer = {
> .init = realview_pbx_timer_init,
> };
>
> -static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
> - char **from, struct meminfo *meminfo)
> +static void realview_pbx_fixup(struct tag *tags, char **from,
> + struct meminfo *meminfo)
> {
> #ifdef CONFIG_SPARSEMEM
> /*
> @@ -335,7 +335,7 @@ static void realview_pbx_fixup(struct machine_desc *mdesc, struct tag *tags,
> meminfo->bank[2].size = SZ_256M;
> meminfo->nr_banks = 3;
> #else
> - realview_fixup(mdesc, tags, from, meminfo);
> + realview_fixup(tags, from, meminfo);
> #endif
> }
>
> diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
> index 834cfb6..3391713 100644
> --- a/arch/arm/mach-s3c2412/mach-smdk2413.c
> +++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
> @@ -92,8 +92,7 @@ static struct platform_device *smdk2413_devices[] __initdata = {
> &s3c_device_usbgadget,
> };
>
> -static void __init smdk2413_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline,
> +static void __init smdk2413_fixup(struct tag *tags, char **cmdline,
> struct meminfo *mi)
> {
> if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
> diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
> index 83544eb..b6ed457 100644
> --- a/arch/arm/mach-s3c2412/mach-vstms.c
> +++ b/arch/arm/mach-s3c2412/mach-vstms.c
> @@ -129,9 +129,8 @@ static struct platform_device *vstms_devices[] __initdata = {
> &s3c_device_nand,
> };
>
> -static void __init vstms_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline,
> - struct meminfo *mi)
> +static void __init vstms_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
> mi->nr_banks=1;
> diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
> index 26257df..6290ce2 100644
> --- a/arch/arm/mach-sa1100/assabet.c
> +++ b/arch/arm/mach-sa1100/assabet.c
> @@ -301,8 +301,7 @@ static void __init get_assabet_scr(void)
> }
>
> static void __init
> -fixup_assabet(struct machine_desc *desc, struct tag *tags,
> - char **cmdline, struct meminfo *mi)
> +fixup_assabet(struct tag *tags, char **cmdline, struct meminfo *mi)
> {
> /* This must be done before any call to machine_has_neponset() */
> map_sa1100_gpio_regs();
> diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
> index 846cd7d..c78ce41 100644
> --- a/arch/arm/mach-tegra/board-harmony.c
> +++ b/arch/arm/mach-tegra/board-harmony.c
> @@ -123,8 +123,8 @@ static struct platform_device *harmony_devices[] __initdata = {
> &harmony_audio_device,
> };
>
> -static void __init tegra_harmony_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init tegra_harmony_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks = 2;
> mi->bank[0].start = PHYS_OFFSET;
> diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
> index ea2f79c..5e6bc77 100644
> --- a/arch/arm/mach-tegra/board-paz00.c
> +++ b/arch/arm/mach-tegra/board-paz00.c
> @@ -84,8 +84,8 @@ static void paz00_usb_init(void)
> platform_device_register(&tegra_ehci3_device);
> }
>
> -static void __init tegra_paz00_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init tegra_paz00_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks = 1;
> mi->bank[0].start = PHYS_OFFSET;
> diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
> index 89a6d2a..652c340 100644
> --- a/arch/arm/mach-tegra/board-trimslice.c
> +++ b/arch/arm/mach-tegra/board-trimslice.c
> @@ -126,8 +126,8 @@ static void trimslice_usb_init(void)
> platform_device_register(&tegra_ehci1_device);
> }
>
> -static void __init tegra_trimslice_fixup(struct machine_desc *desc,
> - struct tag *tags, char **cmdline, struct meminfo *mi)
> +static void __init tegra_trimslice_fixup(struct tag *tags, char **cmdline,
> + struct meminfo *mi)
> {
> mi->nr_banks = 2;
> mi->bank[0].start = PHYS_OFFSET;
> --
> 1.7.4.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [PATCH] clk: provide prepare/unprepare functions
From: Saravana Kannan @ 2011-09-22 17:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922101024.GK17169@n2100.arm.linux.org.uk>
On 09/22/2011 03:10 AM, Russell King - ARM Linux wrote:
> As discussed previously, there's the need on some platforms to run some
> parts of clk_enable() in contexts which can schedule. The solution
> which was agreed upon was to provide clk_prepare() and clk_unprepare()
> to contain this parts, while clk_enable() and clk_disable() perform
> the atomic part.
>
> This patch provides a common definition for clk_prepare() and
> clk_unprepare() in linux/clk.h, and provides an upgrade path for
> existing implementation and drivers: drivers can start using
> clk_prepare() and clk_unprepare() once this patch is merged without
> having to wait for platform support. Platforms can then start to
> provide these additional functions.
>
> Eventually, HAVE_CLK_PREPARE will be removed from the kernel, and
> everyone will have to provide these new APIs.
Glad to see this. Now the drivers and individual arch's can start moving
to these new APIs before we settle on the common infrastructure. Once
the common infrastructure is in, it should hopefully be trivial to move
each arch to it.
> Signed-off-by: Russell King<rmk+kernel@arm.linux.org.uk>
> ---
> include/linux/clk.h | 38 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 38 insertions(+)
>
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 1d37f42..c7eb17d 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,6 +11,8 @@
> #ifndef __LINUX_CLK_H
> #define __LINUX_CLK_H
>
> +#include<linux/kernel.h>
> +
> struct device;
>
> /*
> @@ -41,11 +43,29 @@ struct clk;
> struct clk *clk_get(struct device *dev, const char *id);
>
> /**
> + * clk_prepare - prepare a clock source
> + * @clk: clock source
> + *
> + * This prepares the clock source for use.
Do you want to add a "May NOT be called from atomic context"? Yeah, the
stub makes it obvious, but I think it would be consistent to add the
comment in. No strong opinion though.
Not sure if you care, but LGTM/Ack.
Thanks,
Saravana
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* [PATCH v3 2/2] input: samsung-keypad: Add device tree support
From: Grant Likely @ 2011-09-22 17:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316427553-5033-3-git-send-email-thomas.abraham@linaro.org>
On Mon, Sep 19, 2011 at 03:49:13PM +0530, Thomas Abraham wrote:
> Add device tree based discovery support for Samsung's keypad controller.
>
> Cc: Joonyoung Shim <jy0922.shim@samsung.com>
> Cc: Donghwa Lee <dh09.lee@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
A few things to fix below, but you can add my acked-by when you've
addressed them.
> ---
> .../devicetree/bindings/input/samsung-keypad.txt | 88 ++++++++++
> drivers/input/keyboard/samsung-keypad.c | 179 ++++++++++++++++++--
> 2 files changed, 255 insertions(+), 12 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/input/samsung-keypad.txt
>
> diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt
> new file mode 100644
> index 0000000..ce3e394
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt
> @@ -0,0 +1,88 @@
> +* Samsung's Keypad Controller device tree bindings
> +
> +Samsung's Keypad controller is used to interface a SoC with a matrix-type
> +keypad device. The keypad controller supports multiple row and column lines.
> +A key can be placed at each intersection of a unique row and a unique column.
> +The keypad controller can sense a key-press and key-release and report the
> +event using a interrupt to the cpu.
> +
> +Required SoC Specific Properties:
> +- compatible: should be one of the following
> + - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad
> + controller.
> + - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad
> + controller.
> +
> +- reg: physical base address of the controller and length of memory mapped
> + region.
> +
> +- interrupts: The interrupt number to the cpu.
> +
> +Required Board Specific Properties:
> +- samsung,keypad-num-rows: Number of row lines connected to the keypad
> + controller.
> +
> +- samsung,keypad-num-columns: Number of column lines connected to the
> + keypad controller.
> +
> +- row-gpios: List of gpios used as row lines. The gpio specifier for
> + this property depends on the gpio controller to which these row lines
> + are connected.
> +
> +- col-gpios: List of gpios used as column lines. The gpio specifier for
> + this property depends on the gpio controller to which these column
> + lines are connected.
> +
> +- Keys represented as child nodes: Each key connected to the keypad
> + controller is represented as a child node to the keypad controller
> + device node and should include the following properties.
> + - keypad,row: the row number to which the key is connected.
> + - keypad,column: the column number to which the key is connected.
> + - linux,code: the key-code to be reported when the key is pressed
> + and released.
> +
> +Optional Properties specific to linux:
> +- linux,keypad-no-autorepeat: do no enable autorepeat feature.
> +- linux,keypad-wakeup: use any event on keypad as wakeup event.
> +
> +
> +Example:
> + keypad at 100A0000 {
> + compatible = "samsung,s5pv210-keypad";
> + reg = <0x100A0000 0x100>;
> + interrupts = <173>;
> + samsung,keypad-num-rows = <2>;
> + samsung,keypad-num-columns = <8>;
> + linux,input-no-autorepeat;
> + linux,input-wakeup;
> +
> + row-gpios = <&gpx2 0 3 3 0
> + &gpx2 1 3 3 0>;
> +
> + col-gpios = <&gpx1 0 3 0 0
> + &gpx1 1 3 0 0
> + &gpx1 2 3 0 0
> + &gpx1 3 3 0 0
> + &gpx1 4 3 0 0
> + &gpx1 5 3 0 0
> + &gpx1 6 3 0 0
> + &gpx1 7 3 0 0>;
> +
> + key_1 {
> + keypad,row = <0>;
> + keypad,column = <3>;
> + linux,code = <2>;
> + };
> +
> + key_2 {
> + keypad,row = <0>;
> + keypad,column = <4>;
> + linux,code = <3>;
> + };
> +
> + key_3 {
> + keypad,row = <0>;
> + keypad,column = <5>;
> + linux,code = <4>;
> + };
> + };
Binding looks okay to me.
> diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
> index f689f49..2a477bc 100644
> --- a/drivers/input/keyboard/samsung-keypad.c
> +++ b/drivers/input/keyboard/samsung-keypad.c
> @@ -21,6 +21,8 @@
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> #include <linux/sched.h>
> #include <plat/keypad.h>
>
> @@ -68,31 +70,26 @@ struct samsung_keypad {
> wait_queue_head_t wait;
> bool stopped;
> int irq;
> + enum samsung_keypad_type type;
> unsigned int row_shift;
> unsigned int rows;
> unsigned int cols;
> unsigned int row_state[SAMSUNG_MAX_COLS];
> +#ifdef CONFIG_OF
> + int row_gpios[SAMSUNG_MAX_ROWS];
> + int col_gpios[SAMSUNG_MAX_COLS];
> +#endif
> unsigned short keycodes[];
> };
>
> -static int samsung_keypad_is_s5pv210(struct device *dev)
> -{
> - struct platform_device *pdev = to_platform_device(dev);
> - enum samsung_keypad_type type =
> - platform_get_device_id(pdev)->driver_data;
> -
> - return type == KEYPAD_TYPE_S5PV210;
> -}
> -
> static void samsung_keypad_scan(struct samsung_keypad *keypad,
> unsigned int *row_state)
> {
> - struct device *dev = keypad->input_dev->dev.parent;
> unsigned int col;
> unsigned int val;
>
> for (col = 0; col < keypad->cols; col++) {
> - if (samsung_keypad_is_s5pv210(dev)) {
> + if (keypad->type == KEYPAD_TYPE_S5PV210) {
> val = S5PV210_KEYIFCOLEN_MASK;
> val &= ~(1 << col) << 8;
> } else {
> @@ -235,6 +232,131 @@ static void samsung_keypad_close(struct input_dev *input_dev)
> samsung_keypad_stop(keypad);
> }
>
> +#ifdef CONFIG_OF
> +static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
> + struct device *dev)
> +{
> + struct samsung_keypad_platdata *pdata;
> + struct matrix_keymap_data *keymap_data;
> + uint32_t *keymap, num_rows, num_cols;
> + struct device_node *np = dev->of_node, *key_np;
> + unsigned int key_count = 0;
> +
> + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> + if (!pdata) {
> + dev_err(dev, "could not allocate memory for platform data\n");
> + return NULL;
> + }
> +
> + of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows);
> + of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols);
property_read doesn't touch the values of num_rows or num_cols on
failure. The values need to be initialized if you're going to test
the result value.
> + if (!num_rows || !num_cols) {
> + dev_err(dev, "number of keypad rows/columns not specified\n");
> + return NULL;
> + }
> + pdata->rows = num_rows;
> + pdata->cols = num_cols;
> +
> + keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
> + if (!keymap_data) {
> + dev_err(dev, "could not allocate memory for keymap data\n");
> + return NULL;
> + }
> + pdata->keymap_data = keymap_data;
> +
> + for_each_child_of_node(np, key_np)
> + key_count++;
> +
> + keymap_data->keymap_size = key_count;
> + keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
> + if (!keymap) {
> + dev_err(dev, "could not allocate memory for keymap\n");
> + return NULL;
> + }
> + keymap_data->keymap = keymap;
> +
> + for_each_child_of_node(np, key_np) {
> + u32 row, col, key_code;
> + of_property_read_u32(key_np, "keypad,row", &row);
> + of_property_read_u32(key_np, "keypad,column", &col);
> + of_property_read_u32(key_np, "linux,code", &key_code);
> + *keymap++ = KEY(row, col, key_code);
> + }
> +
> + if (of_get_property(np, "linux,input-no-autorepeat", NULL))
> + pdata->no_autorepeat = true;
> + if (of_get_property(np, "linux,input-wakeup", NULL))
> + pdata->wakeup = true;
> +
> + return pdata;
> +}
> +
> +static void samsung_keypad_parse_dt_gpio(struct device *dev,
> + struct samsung_keypad *keypad)
> +{
> + struct device_node *np = dev->of_node;
> + int gpio, ret, row, col;
> +
> + for (row = 0; row < keypad->rows; row++) {
> + gpio = of_get_named_gpio(np, "row-gpios", row);
> + keypad->row_gpios[row] = gpio;
> + if (!gpio_is_valid(gpio)) {
> + dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
> + row, gpio);
> + continue;
> + }
> +
> + ret = gpio_request(gpio, "keypad-row");
> + if (ret)
> + dev_err(dev, "keypad row[%d] gpio request failed\n",
> + row);
> + }
> +
> + for (col = 0; col < keypad->cols; col++) {
> + gpio = of_get_named_gpio(np, "col-gpios", col);
> + keypad->col_gpios[col] = gpio;
> + if (!gpio_is_valid(gpio)) {
> + dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
> + col, gpio);
> + continue;
> + }
> +
> + ret = gpio_request(col, "keypad-col");
> + if (ret)
> + dev_err(dev, "keypad column[%d] gpio request failed\n",
> + col);
> + }
> +}
> +
> +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
> +{
> + int cnt;
> +
> + for (cnt = 0; cnt < keypad->rows; cnt++)
> + if (gpio_is_valid(keypad->row_gpios[cnt]))
> + gpio_free(keypad->row_gpios[cnt]);
> +
> + for (cnt = 0; cnt < keypad->cols; cnt++)
> + if (gpio_is_valid(keypad->col_gpios[cnt]))
> + gpio_free(keypad->col_gpios[cnt]);
> +}
> +#else
> +static
> +struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
> +{
> + return NULL;
> +}
> +
> +static void samsung_keypad_parse_dt_gpio(struct device *dev,
> + struct samsung_keypad *keypad)
> +{
> +}
> +
> +static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
> +{
> +}
> +#endif
> +
> static int __devinit samsung_keypad_probe(struct platform_device *pdev)
> {
> const struct samsung_keypad_platdata *pdata;
> @@ -246,7 +368,10 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
> unsigned int keymap_size;
> int error;
>
> - pdata = pdev->dev.platform_data;
> + if (pdev->dev.of_node)
> + pdata = samsung_keypad_parse_dt(&pdev->dev);
> + else
> + pdata = pdev->dev.platform_data;
> if (!pdata) {
> dev_err(&pdev->dev, "no platform data defined\n");
> return -EINVAL;
> @@ -303,6 +428,16 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
> keypad->cols = pdata->cols;
> init_waitqueue_head(&keypad->wait);
>
> + if (pdev->dev.of_node) {
> + samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
> +#ifdef CONFIG_OF
> + keypad->type = of_device_is_compatible(pdev->dev.of_node,
> + "samsung,s5pv210-keypad");
> +#endif
This still looks odd. If you move the #ifdef up one line, then you
can remove the empty version of samsung_keypad_parse_dt_gpio(), and
this block won't look so weird.
> + } else {
> + keypad->type = platform_get_device_id(pdev)->driver_data;
> + }
> +
> input_dev->name = pdev->name;
> input_dev->id.bustype = BUS_HOST;
> input_dev->dev.parent = &pdev->dev;
> @@ -343,12 +478,19 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
>
> device_init_wakeup(&pdev->dev, pdata->wakeup);
> platform_set_drvdata(pdev, keypad);
> +
> + if (pdev->dev.of_node) {
> + devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
> + devm_kfree(&pdev->dev, (void *)pdata->keymap_data);
> + devm_kfree(&pdev->dev, (void *)pdata);
> + }
> return 0;
>
> err_free_irq:
> free_irq(keypad->irq, keypad);
> err_put_clk:
> clk_put(keypad->clk);
> + samsung_keypad_dt_gpio_free(keypad);
> err_unmap_base:
> iounmap(keypad->base);
> err_free_mem:
> @@ -374,6 +516,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
> free_irq(keypad->irq, keypad);
>
> clk_put(keypad->clk);
> + samsung_keypad_dt_gpio_free(keypad);
>
> iounmap(keypad->base);
> kfree(keypad);
> @@ -447,6 +590,17 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = {
> };
> #endif
>
> +#ifdef CONFIG_OF
> +static const struct of_device_id samsung_keypad_dt_match[] = {
> + { .compatible = "samsung,s3c6410-keypad" },
> + { .compatible = "samsung,s5pv210-keypad" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
> +#else
> +#define samsung_keypad_dt_match NULL
> +#endif
> +
> static struct platform_device_id samsung_keypad_driver_ids[] = {
> {
> .name = "samsung-keypad",
> @@ -465,6 +619,7 @@ static struct platform_driver samsung_keypad_driver = {
> .driver = {
> .name = "samsung-keypad",
> .owner = THIS_MODULE,
> + .of_match_table = samsung_keypad_dt_match,
> #ifdef CONFIG_PM
> .pm = &samsung_keypad_pm_ops,
> #endif
> --
> 1.6.6.rc2
>
^ permalink raw reply
* [PATCH v2] i2c-tegra: Use the suspend_noirq/resume_noirq not suspend/resume
From: Stephen Warren @ 2011-09-22 17:51 UTC (permalink / raw)
To: linux-arm-kernel
From: Dilan Lee <dilee@nvidia.com>
Various drivers need to use the I2C bus during suspend. Generally, this
is already supported, since devices are suspended based on (the inverse of)
probe order, and an I2C-based device can't probe until the I2C bus upon
which it sits has been probed first.
However, some subsystems, notably ASoC, do not enjoy such simple bus/child
probing relationships. In particular, an ASoC machine driver (and hence a
sound card) may probe very early on before all its required resources are
available. After all required resources become available, the overall
machine driver initialization is performed. Suspend of a sound card occurs
based on the machine driver's probe timing, which may mean suspend occurs
after an I2C bus has been suspended. In turn, components within the sound
card suspend when the overall card suspends. If one of those components
is an I2C device, this may mean the device attempts to suspend after the
I2C bus it sits upon. Conversely, resume may occur before the I2C bus is
available. Consequently, I2C accesses during suspend/resume will fail.
This causes the following issue:
We found the register settings of wm8903(an audio codec) can't be modified
in snd_soc_suspend since I2C bus has been suspended before snd_soc_suspend.
Pop noise will occur when system resume from LP0 if the register settings
of wm8903 haven't be modified correctly in snd_soc_suspend.
To solve this, the I2C bus driver is modified to use suspend_noirq and
resume_noirq instead of suspend and resume. This delays the I2C bus suspend
until after the ASoC card-level suspend, and everything works.
It is acknowledged that this is not an ideal solution. However, this solution
is the best currently available within the kernel.
Suggested alternatives are:
* Implement an explicit dependency management system within the kernel for
device suspend/resume, such that I2C bus would not be suspended before
the sound card that requires it. It is reported that Linus rejected this
proposal since he wanted suspend ordering to be based on probe ordering.
* Enhance device probing such that the ASoC sound card device could defer
its probing until all required resources were available. This would
then cause the overall sound card suspend to occur at an appropriate early
time. Grant Likely was reported to have been working towards this goal.
[swarren: Rewrote patch description to reflect upstream discussion]
Signed-off-by: Dilan Lee <dilee@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
v2: Summarized the email thread in patch description.
Added Arnd/Mark's ack/review tags
drivers/i2c/busses/i2c-tegra.c | 19 +++++++++++++------
1 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b402435..15ad866 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -705,8 +705,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+static int tegra_i2c_suspend_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
i2c_lock_adapter(&i2c_dev->adapter);
@@ -716,8 +717,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int tegra_i2c_resume(struct platform_device *pdev)
+static int tegra_i2c_resume_noirq(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
int ret;
@@ -736,6 +738,14 @@ static int tegra_i2c_resume(struct platform_device *pdev)
return 0;
}
+
+static const struct dev_pm_ops tegra_i2c_dev_pm_ops = {
+ .suspend_noirq = tegra_i2c_suspend_noirq,
+ .resume_noirq = tegra_i2c_resume_noirq,
+};
+#define TEGRA_I2C_DEV_PM_OPS (&tegra_i2c_dev_pm_ops)
+#else
+#define TEGRA_I2C_DEV_PM_OPS NULL
#endif
#if defined(CONFIG_OF)
@@ -752,14 +762,11 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove = tegra_i2c_remove,
-#ifdef CONFIG_PM
- .suspend = tegra_i2c_suspend,
- .resume = tegra_i2c_resume,
-#endif
.driver = {
.name = "tegra-i2c",
.owner = THIS_MODULE,
.of_match_table = tegra_i2c_of_match,
+ .pm = TEGRA_I2C_DEV_PM_OPS,
},
};
--
1.7.0.4
^ permalink raw reply related
* [PATCH] arm/tegra: select AUTO_ZRELADDR by default
From: Peter De Schrijver @ 2011-09-22 17:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <74CDBE0F657A3D45AFBB94109FB122FF1739554CB9@HQMAIL01.nvidia.com>
On Thu, Sep 22, 2011 at 06:26:36PM +0200, Stephen Warren wrote:
> Peter De Schrijver wrote at Thursday, September 22, 2011 7:27 AM:
> > This patch causes the kernel uncompressor to determine the physical address
> > of the SDRAM at runtime. This allows the kernel to boot on both tegra2 and
> > tegra3 even though SDRAM is at different physical addresses on both SoCs.
>
> Since this deals with Tegra, it should be mailed to/cc the Tegra
> Maintainers and mailing list too (I've done that here). get_maintainer.pl
> will no doubt list the main linux-kernel mailing list too.
>
> > Change-Id: I91857a590946bbc54168c04bea3a5bd576d87824
>
> And the internal Change-Id lines should be stripped for upstream
> submissions.
>
Auw indeed. I did it for the previous round, but I really need to write a
script to do this :)
Cheers,
Peter.
^ permalink raw reply
* [PATCH] ARM: S3C64xx: Add LDOVDD supply for CODEC on Cragganmore
From: Mark Brown @ 2011-09-22 18:01 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
arch/arm/mach-s3c64xx/mach-crag6410.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index a53b02e..613c165 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -582,6 +582,7 @@ static struct regulator_init_data pvdd_1v2 __initdata = {
};
static struct regulator_consumer_supply pvdd_1v8_consumers[] __initdata = {
+ REGULATOR_SUPPLY("LDOVDD", "1-001a"),
REGULATOR_SUPPLY("PLLVDD", "1-001a"),
REGULATOR_SUPPLY("DBVDD", "1-001a"),
REGULATOR_SUPPLY("DBVDD1", "1-001a"),
--
1.7.6.3
^ permalink raw reply related
* [PATCH v2] i2c-tegra: Use the suspend_noirq/resume_noirq not suspend/resume
From: Grant Likely @ 2011-09-22 18:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316713892-357-1-git-send-email-swarren@nvidia.com>
On Thu, Sep 22, 2011 at 11:51:32AM -0600, Stephen Warren wrote:
> From: Dilan Lee <dilee@nvidia.com>
>
> Various drivers need to use the I2C bus during suspend. Generally, this
> is already supported, since devices are suspended based on (the inverse of)
> probe order, and an I2C-based device can't probe until the I2C bus upon
> which it sits has been probed first.
>
> However, some subsystems, notably ASoC, do not enjoy such simple bus/child
> probing relationships. In particular, an ASoC machine driver (and hence a
> sound card) may probe very early on before all its required resources are
> available. After all required resources become available, the overall
> machine driver initialization is performed. Suspend of a sound card occurs
> based on the machine driver's probe timing, which may mean suspend occurs
> after an I2C bus has been suspended. In turn, components within the sound
> card suspend when the overall card suspends. If one of those components
> is an I2C device, this may mean the device attempts to suspend after the
> I2C bus it sits upon. Conversely, resume may occur before the I2C bus is
> available. Consequently, I2C accesses during suspend/resume will fail.
>
> This causes the following issue:
>
> We found the register settings of wm8903(an audio codec) can't be modified
> in snd_soc_suspend since I2C bus has been suspended before snd_soc_suspend.
>
> Pop noise will occur when system resume from LP0 if the register settings
> of wm8903 haven't be modified correctly in snd_soc_suspend.
>
> To solve this, the I2C bus driver is modified to use suspend_noirq and
> resume_noirq instead of suspend and resume. This delays the I2C bus suspend
> until after the ASoC card-level suspend, and everything works.
>
> It is acknowledged that this is not an ideal solution. However, this solution
> is the best currently available within the kernel.
>
> Suggested alternatives are:
>
> * Implement an explicit dependency management system within the kernel for
> device suspend/resume, such that I2C bus would not be suspended before
> the sound card that requires it. It is reported that Linus rejected this
> proposal since he wanted suspend ordering to be based on probe ordering.
This really should be revisted. That was in the context of full
system suspend, but we're now in a world of runtime suspend which
absolutely does need dependency tracking or reference counting to get
the ordering right.
> * Enhance device probing such that the ASoC sound card device could defer
> its probing until all required resources were available. This would
> then cause the overall sound card suspend to occur at an appropriate early
> time. Grant Likely was reported to have been working towards this goal.
Yes, I'll send you my current patch for you to look at. One of the
engineers from Linaro is going to be pushing that patch set forward.
However, I don't know if it helps with this problem because I believe
that the suspend order is based on the implicit probe order of
devices, but my patch allows drivers to cause the probe order to get
rearranged at runtime. I don't believe there is a global list showing
the order that devices successfully got probed, but I may be wrong
here.
g.
>
> [swarren: Rewrote patch description to reflect upstream discussion]
>
> Signed-off-by: Dilan Lee <dilee@nvidia.com>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
> ---
> v2: Summarized the email thread in patch description.
> Added Arnd/Mark's ack/review tags
>
> drivers/i2c/busses/i2c-tegra.c | 19 +++++++++++++------
> 1 files changed, 13 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index b402435..15ad866 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -705,8 +705,9 @@ static int tegra_i2c_remove(struct platform_device *pdev)
> }
>
> #ifdef CONFIG_PM
> -static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
> +static int tegra_i2c_suspend_noirq(struct device *dev)
> {
> + struct platform_device *pdev = to_platform_device(dev);
> struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
>
> i2c_lock_adapter(&i2c_dev->adapter);
> @@ -716,8 +717,9 @@ static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
> return 0;
> }
>
> -static int tegra_i2c_resume(struct platform_device *pdev)
> +static int tegra_i2c_resume_noirq(struct device *dev)
> {
> + struct platform_device *pdev = to_platform_device(dev);
> struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
> int ret;
>
> @@ -736,6 +738,14 @@ static int tegra_i2c_resume(struct platform_device *pdev)
>
> return 0;
> }
> +
> +static const struct dev_pm_ops tegra_i2c_dev_pm_ops = {
> + .suspend_noirq = tegra_i2c_suspend_noirq,
> + .resume_noirq = tegra_i2c_resume_noirq,
> +};
> +#define TEGRA_I2C_DEV_PM_OPS (&tegra_i2c_dev_pm_ops)
> +#else
> +#define TEGRA_I2C_DEV_PM_OPS NULL
> #endif
>
> #if defined(CONFIG_OF)
> @@ -752,14 +762,11 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
> static struct platform_driver tegra_i2c_driver = {
> .probe = tegra_i2c_probe,
> .remove = tegra_i2c_remove,
> -#ifdef CONFIG_PM
> - .suspend = tegra_i2c_suspend,
> - .resume = tegra_i2c_resume,
> -#endif
> .driver = {
> .name = "tegra-i2c",
> .owner = THIS_MODULE,
> .of_match_table = tegra_i2c_of_match,
> + .pm = TEGRA_I2C_DEV_PM_OPS,
> },
> };
>
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* [PATCH] arm/tegra: select AUTO_ZRELADDR by default
From: Colin Cross @ 2011-09-22 18:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922175800.GC21166@tbergstrom-lnx.Nvidia.com>
On Thu, Sep 22, 2011 at 10:58 AM, Peter De Schrijver
<pdeschrijver@nvidia.com> wrote:
> On Thu, Sep 22, 2011 at 06:26:36PM +0200, Stephen Warren wrote:
>> Peter De Schrijver wrote at Thursday, September 22, 2011 7:27 AM:
>> > This patch causes the kernel uncompressor to determine the physical address
>> > of the SDRAM at runtime. This allows the kernel to boot on both tegra2 and
>> > tegra3 even though SDRAM is at different physical addresses on both SoCs.
>>
>> Since this deals with Tegra, it should be mailed to/cc the Tegra
>> Maintainers and mailing list too (I've done that here). get_maintainer.pl
>> will no doubt list the main linux-kernel mailing list too.
>>
>> > Change-Id: I91857a590946bbc54168c04bea3a5bd576d87824
>>
>> And the internal Change-Id lines should be stripped for upstream
>> submissions.
>>
>
> Auw indeed. I did it for the previous round, but I really need to write a
> script to do this :)
I use this alias in my .gitconfig:
[alias]
nochangeid = filter-branch --msg-filter \"sed -e '/^Change-Id:/Id'\"
Then:
git nochangeid <from>..<to>
rewrites all the patch commits without change ids.
^ permalink raw reply
* [PATCH V7 1/5] AHCI Add the AHCI SATA feature on the MX53 platforms
From: Jeff Garzik @ 2011-09-22 18:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJNCFVLm=bUMvXq7acke7Bd_tiV+b1=HjVp37KwtYyGsZHa+OQ@mail.gmail.com>
On 09/21/2011 03:05 AM, Richard Zhu wrote:
> Hi Sascha:
> One proposal about how to convert the ahci driver to devicetree in future.
> ahci driver system can make a reference to the evolution of the sdhc driver.
>
> * separate the ahci to ahci common codes, ahci-pci driver and
> ahci-platform driver.
We already have this, with libahci.
"libahci" == ahci common code
"ahci" == AHCI PCI driver
"ahci-platform" == AHCI platform driver
Jeff
^ permalink raw reply
* [PATCH v2] i2c-tegra: Use the suspend_noirq/resume_noirq not suspend/resume
From: Mark Brown @ 2011-09-22 18:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922180335.GQ17168@ponder.secretlab.ca>
On Thu, Sep 22, 2011 at 12:03:35PM -0600, Grant Likely wrote:
> On Thu, Sep 22, 2011 at 11:51:32AM -0600, Stephen Warren wrote:
> > * Implement an explicit dependency management system within the kernel for
> > device suspend/resume, such that I2C bus would not be suspended before
> > the sound card that requires it. It is reported that Linus rejected this
> > proposal since he wanted suspend ordering to be based on probe ordering.
> This really should be revisted. That was in the context of full
> system suspend, but we're now in a world of runtime suspend which
> absolutely does need dependency tracking or reference counting to get
> the ordering right.
FWIW this was one of the bigger issues in the PM miniconference in Santa
Rosa, though a lot of the discission involved explaining the issues to
some of the x86 guys and there wasn't mssive progress on solutions.
> > * Enhance device probing such that the ASoC sound card device could defer
> > its probing until all required resources were available. This would
> > then cause the overall sound card suspend to occur at an appropriate early
> > time. Grant Likely was reported to have been working towards this goal.
> Yes, I'll send you my current patch for you to look at. One of the
> engineers from Linaro is going to be pushing that patch set forward.
> However, I don't know if it helps with this problem because I believe
> that the suspend order is based on the implicit probe order of
> devices, but my patch allows drivers to cause the probe order to get
> rearranged at runtime. I don't believe there is a global list showing
> the order that devices successfully got probed, but I may be wrong
> here.
Yes, I'm not convinced it'll change anything here. Though I guess it
should be a simple matter of programming to move devices around the list
depending on when they probe.
^ permalink raw reply
* [RFC] Shrink sched_clock some more
From: Nicolas Pitre @ 2011-09-22 18:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922153611.GC8072@n2100.arm.linux.org.uk>
On Thu, 22 Sep 2011, Russell King - ARM Linux wrote:
> ... by getting rid of the fixed-constant optimization, and moving the
> update code into arch/arm/kernel/sched_clock.c.
>
> Platforms now only have to supply a function to read the sched_clock
> register, and some basic information such as the number of significant
> bits and the tick rate.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Nice. Too bad for the fixed-constant optimization, but it wasn't used
enough to justify the bloat.
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> ---
> arch/arm/include/asm/sched_clock.h | 98 +--------------------------------
> arch/arm/kernel/sched_clock.c | 91 ++++++++++++++++++++++++++++--
> arch/arm/mach-ixp4xx/common.c | 15 +----
> arch/arm/mach-mmp/time.c | 15 +----
> arch/arm/mach-omap1/time.c | 27 +--------
> arch/arm/mach-omap2/timer.c | 21 +------
> arch/arm/mach-pxa/time.c | 23 +-------
> arch/arm/mach-sa1100/time.c | 27 +--------
> arch/arm/mach-tegra/timer.c | 23 +-------
> arch/arm/mach-u300/timer.c | 22 +------
> arch/arm/plat-iop/time.c | 15 +----
> arch/arm/plat-mxc/time.c | 15 +----
> arch/arm/plat-nomadik/timer.c | 25 +-------
> arch/arm/plat-omap/counter_32k.c | 39 +------------
> arch/arm/plat-orion/time.c | 16 +----
> arch/arm/plat-s5p/s5p-time.c | 29 +---------
> arch/arm/plat-versatile/sched-clock.c | 26 +--------
> 17 files changed, 131 insertions(+), 396 deletions(-)
>
> diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h
> index c8e6ddf..2026a0c 100644
> --- a/arch/arm/include/asm/sched_clock.h
> +++ b/arch/arm/include/asm/sched_clock.h
> @@ -11,109 +11,13 @@
> #include <linux/kernel.h>
> #include <linux/types.h>
>
> -struct clock_data {
> - u64 epoch_ns;
> - u32 epoch_cyc;
> - u32 epoch_cyc_copy;
> - u32 mult;
> - u32 shift;
> -};
> -
> -#define DEFINE_CLOCK_DATA(name) struct clock_data name
> -
> -static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
> -{
> - return (cyc * mult) >> shift;
> -}
> -
> -/*
> - * Atomically update the sched_clock epoch. Your update callback will
> - * be called from a timer before the counter wraps - read the current
> - * counter value, and call this function to safely move the epochs
> - * forward. Only use this from the update callback.
> - */
> -static inline void update_sched_clock(struct clock_data *cd, u32 cyc, u32 mask)
> -{
> - unsigned long flags;
> - u64 ns = cd->epoch_ns +
> - cyc_to_ns((cyc - cd->epoch_cyc) & mask, cd->mult, cd->shift);
> -
> - /*
> - * Write epoch_cyc and epoch_ns in a way that the update is
> - * detectable in cyc_to_fixed_sched_clock().
> - */
> - raw_local_irq_save(flags);
> - cd->epoch_cyc = cyc;
> - smp_wmb();
> - cd->epoch_ns = ns;
> - smp_wmb();
> - cd->epoch_cyc_copy = cyc;
> - raw_local_irq_restore(flags);
> -}
> -
> -/*
> - * If your clock rate is known at compile time, using this will allow
> - * you to optimize the mult/shift loads away. This is paired with
> - * init_fixed_sched_clock() to ensure that your mult/shift are correct.
> - */
> -static inline unsigned long long cyc_to_fixed_sched_clock(struct clock_data *cd,
> - u32 cyc, u32 mask, u32 mult, u32 shift)
> -{
> - u64 epoch_ns;
> - u32 epoch_cyc;
> -
> - /*
> - * Load the epoch_cyc and epoch_ns atomically. We do this by
> - * ensuring that we always write epoch_cyc, epoch_ns and
> - * epoch_cyc_copy in strict order, and read them in strict order.
> - * If epoch_cyc and epoch_cyc_copy are not equal, then we're in
> - * the middle of an update, and we should repeat the load.
> - */
> - do {
> - epoch_cyc = cd->epoch_cyc;
> - smp_rmb();
> - epoch_ns = cd->epoch_ns;
> - smp_rmb();
> - } while (epoch_cyc != cd->epoch_cyc_copy);
> -
> - return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, mult, shift);
> -}
> -
> -/*
> - * Otherwise, you need to use this, which will obtain the mult/shift
> - * from the clock_data structure. Use init_sched_clock() with this.
> - */
> -static inline unsigned long long cyc_to_sched_clock(struct clock_data *cd,
> - u32 cyc, u32 mask)
> -{
> - return cyc_to_fixed_sched_clock(cd, cyc, mask, cd->mult, cd->shift);
> -}
> -
> /*
> * Initialize the clock data - calculate the appropriate multiplier
> * and shift. Also setup a timer to ensure that the epoch is refreshed
> * at the appropriate time interval, which will call your update
> * handler.
> */
> -void init_sched_clock(struct clock_data *, void (*)(void),
> - unsigned int, unsigned long);
> -
> -/*
> - * Use this initialization function rather than init_sched_clock() if
> - * you're using cyc_to_fixed_sched_clock, which will warn if your
> - * constants are incorrect.
> - */
> -static inline void init_fixed_sched_clock(struct clock_data *cd,
> - void (*update)(void), unsigned int bits, unsigned long rate,
> - u32 mult, u32 shift)
> -{
> - init_sched_clock(cd, update, bits, rate);
> - if (cd->mult != mult || cd->shift != shift) {
> - pr_crit("sched_clock: wrong multiply/shift: %u>>%u vs calculated %u>>%u\n"
> - "sched_clock: fix multiply/shift to avoid scheduler hiccups\n",
> - mult, shift, cd->mult, cd->shift);
> - }
> -}
> +void init_sched_clock(u32 (*)(void), unsigned int, unsigned long);
>
> extern void sched_clock_postinit(void);
>
> diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
> index 9a46370..dfee812 100644
> --- a/arch/arm/kernel/sched_clock.c
> +++ b/arch/arm/kernel/sched_clock.c
> @@ -14,28 +14,107 @@
>
> #include <asm/sched_clock.h>
>
> +struct clock_data {
> + u64 epoch_ns;
> + u32 epoch_cyc;
> + u32 epoch_cyc_copy;
> + u32 mult;
> + u32 shift;
> + u32 mask;
> +};
> +
> static void sched_clock_poll(unsigned long wrap_ticks);
> static DEFINE_TIMER(sched_clock_timer, sched_clock_poll, 0, 0);
> -static void (*sched_clock_update_fn)(void);
> +static u32 (*sched_clock_read_fn)(void);
> +static struct clock_data sched_clock_data;
> +
> +static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
> +{
> + return (cyc * mult) >> shift;
> +}
> +
> +/*
> + * Atomically update the sched_clock epoch. Your update callback will
> + * be called from a timer before the counter wraps - read the current
> + * counter value, and call this function to safely move the epochs
> + * forward. Only use this from the update callback.
> + */
> +static inline void update_sched_clock(struct clock_data *cd, u32 cyc, u32 mask)
> +{
> + unsigned long flags;
> + u64 ns = cd->epoch_ns +
> + cyc_to_ns((cyc - cd->epoch_cyc) & mask, cd->mult, cd->shift);
> +
> + /*
> + * Write epoch_cyc and epoch_ns in a way that the update is
> + * detectable in cyc_to_sched_clock().
> + */
> + raw_local_irq_save(flags);
> + cd->epoch_cyc = cyc;
> + smp_wmb();
> + cd->epoch_ns = ns;
> + smp_wmb();
> + cd->epoch_cyc_copy = cyc;
> + raw_local_irq_restore(flags);
> +}
> +
> +static inline unsigned long long cyc_to_sched_clock(struct clock_data *cd,
> + u32 cyc, u32 mask)
> +{
> + u64 epoch_ns;
> + u32 epoch_cyc;
> +
> + /*
> + * Load the epoch_cyc and epoch_ns atomically. We do this by
> + * ensuring that we always write epoch_cyc, epoch_ns and
> + * epoch_cyc_copy in strict order, and read them in strict order.
> + * If epoch_cyc and epoch_cyc_copy are not equal, then we're in
> + * the middle of an update, and we should repeat the load.
> + */
> + do {
> + epoch_cyc = cd->epoch_cyc;
> + smp_rmb();
> + epoch_ns = cd->epoch_ns;
> + smp_rmb();
> + } while (epoch_cyc != cd->epoch_cyc_copy);
> +
> + return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask,
> + cd->mult, cd->shift);
> +}
>
> static void sched_clock_poll(unsigned long wrap_ticks)
> {
> + struct clock_data *cd = &sched_clock_data;
> mod_timer(&sched_clock_timer, round_jiffies(jiffies + wrap_ticks));
> - sched_clock_update_fn();
> + update_sched_clock(cd, sched_clock_read_fn(), cd->mask);
> }
>
> -void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> +unsigned long long notrace sched_clock(void)
> +{
> + struct clock_data *cd = &sched_clock_data;
> + u32 cyc = 0;
> +
> + if (sched_clock_read_fn)
> + cyc = sched_clock_read_fn();
> +
> + return cyc_to_sched_clock(cd, cyc, cd->mask);
> +}
> +
> +void __init init_sched_clock(u32 (*read)(void),
> unsigned int clock_bits, unsigned long rate)
> {
> + struct clock_data *cd = &sched_clock_data;
> unsigned long r, w;
> u64 res, wrap;
> char r_unit;
>
> - sched_clock_update_fn = update;
> + sched_clock_read_fn = read;
>
> /* calculate the mult/shift to convert counter ticks to ns. */
> clocks_calc_mult_shift(&cd->mult, &cd->shift, rate, NSEC_PER_SEC, 0);
>
> + cd->mask = (1ULL << clock_bits) - 1;
> +
> r = rate;
> if (r >= 4000000) {
> r /= 1000000;
> @@ -46,7 +125,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> }
>
> /* calculate how many ns until we wrap */
> - wrap = cyc_to_ns((1ULL << clock_bits) - 1, cd->mult, cd->shift);
> + wrap = cyc_to_ns(cd->mask, cd->mult, cd->shift);
> do_div(wrap, NSEC_PER_MSEC);
> w = wrap;
>
> @@ -60,7 +139,7 @@ void __init init_sched_clock(struct clock_data *cd, void (*update)(void),
> * sets the initial epoch.
> */
> sched_clock_timer.data = msecs_to_jiffies(w - (w / 10));
> - update();
> + update_sched_clock(cd, read(), cd->mask);
>
> /*
> * Ensure that sched_clock() starts off at 0ns
> diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
> index 0777257..2951db0 100644
> --- a/arch/arm/mach-ixp4xx/common.c
> +++ b/arch/arm/mach-ixp4xx/common.c
> @@ -402,18 +402,9 @@ void __init ixp4xx_sys_init(void)
> /*
> * sched_clock()
> */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> +static u32 notrace ixp4xx_sched_clock_read(void)
> {
> - u32 cyc = *IXP4XX_OSTS;
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace ixp4xx_update_sched_clock(void)
> -{
> - u32 cyc = *IXP4XX_OSTS;
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return *IXP4XX_OSTS;
> }
>
> /*
> @@ -429,7 +420,7 @@ unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
> EXPORT_SYMBOL(ixp4xx_timer_freq);
> static void __init ixp4xx_clocksource_init(void)
> {
> - init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq);
> + init_sched_clock(ixp4xx_sched_clock_read, 32, ixp4xx_timer_freq);
>
> clocksource_mmio_init(NULL, "OSTS", ixp4xx_timer_freq, 200, 32,
> ixp4xx_clocksource_read);
> diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
> index 4e91ee6..11f2bf1 100644
> --- a/arch/arm/mach-mmp/time.c
> +++ b/arch/arm/mach-mmp/time.c
> @@ -42,8 +42,6 @@
> #define MAX_DELTA (0xfffffffe)
> #define MIN_DELTA (16)
>
> -static DEFINE_CLOCK_DATA(cd);
> -
> /*
> * FIXME: the timer needs some delay to stablize the counter capture
> */
> @@ -59,16 +57,9 @@ static inline uint32_t timer_read(void)
> return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
> }
>
> -unsigned long long notrace sched_clock(void)
> +static u32 notrace mmp_sched_clock_read(void)
> {
> - u32 cyc = timer_read();
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace mmp_update_sched_clock(void)
> -{
> - u32 cyc = timer_read();
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return timer_read();
> }
>
> static irqreturn_t timer_interrupt(int irq, void *dev_id)
> @@ -201,7 +192,7 @@ void __init timer_init(int irq)
> {
> timer_config();
>
> - init_sched_clock(&cd, mmp_update_sched_clock, 32, CLOCK_TICK_RATE);
> + init_sched_clock(mmp_sched_clock_read, 32, CLOCK_TICK_RATE);
>
> ckevt.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt.shift);
> ckevt.max_delta_ns = clockevent_delta2ns(MAX_DELTA, &ckevt);
> diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
> index a183777..e6df086 100644
> --- a/arch/arm/mach-omap1/time.c
> +++ b/arch/arm/mach-omap1/time.c
> @@ -190,30 +190,9 @@ static __init void omap_init_mpu_timer(unsigned long rate)
> * ---------------------------------------------------------------------------
> */
>
> -static DEFINE_CLOCK_DATA(cd);
> -
> -static inline unsigned long long notrace _omap_mpu_sched_clock(void)
> -{
> - u32 cyc = ~omap_mpu_timer_read(1);
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -#ifndef CONFIG_OMAP_32K_TIMER
> -unsigned long long notrace sched_clock(void)
> -{
> - return _omap_mpu_sched_clock();
> -}
> -#else
> -static unsigned long long notrace omap_mpu_sched_clock(void)
> -{
> - return _omap_mpu_sched_clock();
> -}
> -#endif
> -
> -static void notrace mpu_update_sched_clock(void)
> +static u32 notrace omap_mpu_sched_clock_read(void)
> {
> - u32 cyc = ~omap_mpu_timer_read(1);
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return = ~omap_mpu_timer_read(1);
> }
>
> static void __init omap_init_clocksource(unsigned long rate)
> @@ -223,7 +202,7 @@ static void __init omap_init_clocksource(unsigned long rate)
> "%s: can't register clocksource!\n";
>
> omap_mpu_timer_start(1, ~0, 1);
> - init_sched_clock(&cd, mpu_update_sched_clock, 32, rate);
> + init_sched_clock(omap_mpu_sched_clock_read, 32, rate);
>
> if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
> 300, 32, clocksource_mmio_readl_down))
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index cf1de7d..a0d4199 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -248,7 +248,6 @@ static struct omap_dm_timer clksrc;
> /*
> * clocksource
> */
> -static DEFINE_CLOCK_DATA(cd);
> static cycle_t clocksource_read_cycles(struct clocksource *cs)
> {
> return (cycle_t)__omap_dm_timer_read_counter(clksrc.io_base, 1);
> @@ -262,23 +261,9 @@ static struct clocksource clocksource_gpt = {
> .flags = CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
> -static void notrace dmtimer_update_sched_clock(void)
> +static u32 notrace dmtimer_sched_clock_read(void)
> {
> - u32 cyc;
> -
> - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
> -
> - update_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = 0;
> -
> - if (clksrc.reserved)
> - cyc = __omap_dm_timer_read_counter(clksrc.io_base, 1);
> -
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> + return __omap_dm_timer_read_counter(clksrc.io_base, 1);
> }
>
> /* Setup free-running counter for clocksource */
> @@ -295,7 +280,7 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
>
> __omap_dm_timer_load_start(clksrc.io_base,
> OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
> - init_sched_clock(&cd, dmtimer_update_sched_clock, 32, clksrc.rate);
> + init_sched_clock(dmtimer_sched_clock_read, 32, clksrc.rate);
>
> if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
> pr_err("Could not register clocksource %s\n",
> diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
> index de68470..ff0b1a6 100644
> --- a/arch/arm/mach-pxa/time.c
> +++ b/arch/arm/mach-pxa/time.c
> @@ -24,26 +24,9 @@
> #include <asm/sched_clock.h>
> #include <mach/regs-ost.h>
>
> -/*
> - * This is PXA's sched_clock implementation. This has a resolution
> - * of at least 308 ns and a maximum value of 208 days.
> - *
> - * The return value is guaranteed to be monotonic in that range as
> - * long as there is always less than 582 seconds between successive
> - * calls to sched_clock() which should always be the case in practice.
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = OSCR;
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace pxa_update_sched_clock(void)
> +static u32 notrace pxa_sched_clock_read(void)
> {
> - u32 cyc = OSCR;
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return OSCR;
> }
>
>
> @@ -119,7 +102,7 @@ static void __init pxa_timer_init(void)
> OIER = 0;
> OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
>
> - init_sched_clock(&cd, pxa_update_sched_clock, 32, clock_tick_rate);
> + init_sched_clock(pxa_sched_clock_read, 32, clock_tick_rate);
>
> clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4);
> ckevt_pxa_osmr0.max_delta_ns =
> diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
> index fa66024..ebaa64e 100644
> --- a/arch/arm/mach-sa1100/time.c
> +++ b/arch/arm/mach-sa1100/time.c
> @@ -20,29 +20,9 @@
> #include <asm/sched_clock.h>
> #include <mach/hardware.h>
>
> -/*
> - * This is the SA11x0 sched_clock implementation.
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -/*
> - * Constants generated by clocks_calc_mult_shift(m, s, 3.6864MHz,
> - * NSEC_PER_SEC, 60).
> - * This gives a resolution of about 271ns and a wrap period of about 19min.
> - */
> -#define SC_MULT 2275555556u
> -#define SC_SHIFT 23
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = OSCR;
> - return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
> -}
> -
> -static void notrace sa1100_update_sched_clock(void)
> +static u32 notrace sa1100_sched_clock_read(void)
> {
> - u32 cyc = OSCR;
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return OSCR;
> }
>
> #define MIN_OSCR_DELTA 2
> @@ -109,8 +89,7 @@ static void __init sa1100_timer_init(void)
> OIER = 0;
> OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
>
> - init_fixed_sched_clock(&cd, sa1100_update_sched_clock, 32,
> - 3686400, SC_MULT, SC_SHIFT);
> + init_sched_clock(sa1100_sched_clock_read, 32, 3686400);
>
> clockevents_calc_mult_shift(&ckevt_sa1100_osmr0, 3686400, 4);
> ckevt_sa1100_osmr0.max_delta_ns =
> diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
> index 9035042..fdf1e12 100644
> --- a/arch/arm/mach-tegra/timer.c
> +++ b/arch/arm/mach-tegra/timer.c
> @@ -106,25 +106,9 @@ static struct clock_event_device tegra_clockevent = {
> .set_mode = tegra_timer_set_mode,
> };
>
> -static DEFINE_CLOCK_DATA(cd);
> -
> -/*
> - * Constants generated by clocks_calc_mult_shift(m, s, 1MHz, NSEC_PER_SEC, 60).
> - * This gives a resolution of about 1us and a wrap period of about 1h11min.
> - */
> -#define SC_MULT 4194304000u
> -#define SC_SHIFT 22
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = timer_readl(TIMERUS_CNTR_1US);
> - return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
> -}
> -
> -static void notrace tegra_update_sched_clock(void)
> +static u32 notrace tegra_sched_clock_read(void)
> {
> - u32 cyc = timer_readl(TIMERUS_CNTR_1US);
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return timer_readl(TIMERUS_CNTR_1US);
> }
>
> /*
> @@ -218,8 +202,7 @@ static void __init tegra_init_timer(void)
> WARN(1, "Unknown clock rate");
> }
>
> - init_fixed_sched_clock(&cd, tegra_update_sched_clock, 32,
> - 1000000, SC_MULT, SC_SHIFT);
> + init_sched_clock(tegra_sched_clock_read, 32, 1000000);
>
> if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
> "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) {
> diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
> index 5f51bde..2301f71 100644
> --- a/arch/arm/mach-u300/timer.c
> +++ b/arch/arm/mach-u300/timer.c
> @@ -330,25 +330,9 @@ static struct irqaction u300_timer_irq = {
> .handler = u300_timer_interrupt,
> };
>
> -/*
> - * Override the global weak sched_clock symbol with this
> - * local implementation which uses the clocksource to get some
> - * better resolution when scheduling the kernel. We accept that
> - * this wraps around for now, since it is just a relative time
> - * stamp. (Inspired by OMAP implementation.)
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace u300_update_sched_clock(void)
> +static u32 notrace u300_sched_clock_read(void)
> {
> - u32 cyc = readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
> }
>
>
> @@ -366,7 +350,7 @@ static void __init u300_timer_init(void)
> clk_enable(clk);
> rate = clk_get_rate(clk);
>
> - init_sched_clock(&cd, u300_update_sched_clock, 32, rate);
> + init_sched_clock(u300_sched_clock_read, 32, rate);
>
> /*
> * Disable the "OS" and "DD" timers - these are designed for Symbian!
> diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
> index 7cdc516..b038636 100644
> --- a/arch/arm/plat-iop/time.c
> +++ b/arch/arm/plat-iop/time.c
> @@ -51,21 +51,12 @@ static struct clocksource iop_clocksource = {
> .flags = CLOCK_SOURCE_IS_CONTINUOUS,
> };
>
> -static DEFINE_CLOCK_DATA(cd);
> -
> /*
> * IOP sched_clock() implementation via its clocksource.
> */
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = 0xffffffffu - read_tcr1();
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace iop_update_sched_clock(void)
> +static u32 notrace iop_sched_clock_read(void)
> {
> - u32 cyc = 0xffffffffu - read_tcr1();
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return cyc = 0xffffffffu - read_tcr1();
> }
>
> /*
> @@ -151,7 +142,7 @@ void __init iop_init_time(unsigned long tick_rate)
> {
> u32 timer_ctl;
>
> - init_sched_clock(&cd, iop_update_sched_clock, 32, tick_rate);
> + init_sched_clock(iop_sched_clock_read, 32, tick_rate);
>
> ticks_per_jiffy = DIV_ROUND_CLOSEST(tick_rate, HZ);
> iop_tick_rate = tick_rate;
> diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
> index 4b0fe28..b74f721 100644
> --- a/arch/arm/plat-mxc/time.c
> +++ b/arch/arm/plat-mxc/time.c
> @@ -108,18 +108,9 @@ static void gpt_irq_acknowledge(void)
>
> static void __iomem *sched_clock_reg;
>
> -static DEFINE_CLOCK_DATA(cd);
> -unsigned long long notrace sched_clock(void)
> +static u32 notrace mxc_sched_clock_read(void)
> {
> - cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
> -
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace mxc_update_sched_clock(void)
> -{
> - cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return __raw_readl(sched_clock_reg);
> }
>
> static int __init mxc_clocksource_init(struct clk *timer_clk)
> @@ -129,7 +120,7 @@ static int __init mxc_clocksource_init(struct clk *timer_clk)
>
> sched_clock_reg = reg;
>
> - init_sched_clock(&cd, mxc_update_sched_clock, 32, c);
> + init_sched_clock(mxc_sched_clock_read, 32, c);
> return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
> clocksource_mmio_readl_up);
> }
> diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
> index ef74e15..6e38ed1 100644
> --- a/arch/arm/plat-nomadik/timer.c
> +++ b/arch/arm/plat-nomadik/timer.c
> @@ -25,28 +25,9 @@
>
> void __iomem *mtu_base; /* Assigned by machine code */
>
> -/*
> - * Override the global weak sched_clock symbol with this
> - * local implementation which uses the clocksource to get some
> - * better resolution when scheduling the kernel.
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc;
> -
> - if (unlikely(!mtu_base))
> - return 0;
> -
> - cyc = -readl(mtu_base + MTU_VAL(0));
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -static void notrace nomadik_update_sched_clock(void)
> +static u32 notrace nomadik_sched_clock_read(void)
> {
> - u32 cyc = -readl(mtu_base + MTU_VAL(0));
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return -readl(mtu_base + MTU_VAL(0));
> }
>
> /* Clockevent device: use one-shot mode */
> @@ -154,7 +135,7 @@ void __init nmdk_timer_init(void)
> pr_err("timer: failed to initialize clock source %s\n",
> "mtu_0");
>
> - init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate);
> + init_sched_clock(nomadik_sched_clock_read, 32, rate);
>
> /* Timer 1 is used for events */
>
> diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
> index a6cbb71..1faa7ce 100644
> --- a/arch/arm/plat-omap/counter_32k.c
> +++ b/arch/arm/plat-omap/counter_32k.c
> @@ -37,41 +37,9 @@ static void __iomem *timer_32k_base;
>
> #define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
>
> -/*
> - * Returns current time from boot in nsecs. It's OK for this to wrap
> - * around for now, as it's just a relative time stamp.
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -/*
> - * Constants generated by clocks_calc_mult_shift(m, s, 32768, NSEC_PER_SEC, 60).
> - * This gives a resolution of about 30us and a wrap period of about 36hrs.
> - */
> -#define SC_MULT 4000000000u
> -#define SC_SHIFT 17
> -
> -static inline unsigned long long notrace _omap_32k_sched_clock(void)
> -{
> - u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0;
> - return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT);
> -}
> -
> -#if defined(CONFIG_OMAP_32K_TIMER) && !defined(CONFIG_OMAP_MPU_TIMER)
> -unsigned long long notrace sched_clock(void)
> -{
> - return _omap_32k_sched_clock();
> -}
> -#else
> -unsigned long long notrace omap_32k_sched_clock(void)
> -{
> - return _omap_32k_sched_clock();
> -}
> -#endif
> -
> -static void notrace omap_update_sched_clock(void)
> +static inline u32 notrace omap_32k_sched_clock_read(void)
> {
> - u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0;
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return __raw_readl(timer_32k_base);
> }
>
> /**
> @@ -147,8 +115,7 @@ int __init omap_init_clocksource_32k(void)
> clocksource_mmio_readl_up))
> printk(err, "32k_counter");
>
> - init_fixed_sched_clock(&cd, omap_update_sched_clock, 32,
> - 32768, SC_MULT, SC_SHIFT);
> + init_sched_clock(omap_32k_sched_clock_read, 32, 32768);
> }
> return 0;
> }
> diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
> index 69a6136..34e8224 100644
> --- a/arch/arm/plat-orion/time.c
> +++ b/arch/arm/plat-orion/time.c
> @@ -60,24 +60,14 @@ static u32 ticks_per_jiffy;
> * Orion's sched_clock implementation. It has a resolution of
> * at least 7.5ns (133MHz TCLK).
> */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF);
> - return cyc_to_sched_clock(&cd, cyc, (u32)~0);
> -}
> -
> -
> -static void notrace orion_update_sched_clock(void)
> +static u32 notrace orion_sched_clock_read(void)
> {
> - u32 cyc = ~readl(timer_base + TIMER0_VAL_OFF);
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return = ~readl(timer_base + TIMER0_VAL_OFF);
> }
>
> static void __init setup_sched_clock(unsigned long tclk)
> {
> - init_sched_clock(&cd, orion_update_sched_clock, 32, tclk);
> + init_sched_clock(orion_sched_clock_read, 32, tclk);
> }
>
> /*
> diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
> index c833e7b..6fc1121 100644
> --- a/arch/arm/plat-s5p/s5p-time.c
> +++ b/arch/arm/plat-s5p/s5p-time.c
> @@ -314,33 +314,10 @@ static void __iomem *s5p_timer_reg(void)
> return S3C_TIMERREG(offset);
> }
>
> -/*
> - * Override the global weak sched_clock symbol with this
> - * local implementation which uses the clocksource to get some
> - * better resolution when scheduling the kernel. We accept that
> - * this wraps around for now, since it is just a relative time
> - * stamp. (Inspired by U300 implementation.)
> - */
> -static DEFINE_CLOCK_DATA(cd);
> -
> -unsigned long long notrace sched_clock(void)
> +static u32 notrace s5p_sched_clock_read(void)
> {
> void __iomem *reg = s5p_timer_reg();
> -
> - if (!reg)
> - return 0;
> -
> - return cyc_to_sched_clock(&cd, ~__raw_readl(reg), (u32)~0);
> -}
> -
> -static void notrace s5p_update_sched_clock(void)
> -{
> - void __iomem *reg = s5p_timer_reg();
> -
> - if (!reg)
> - return;
> -
> - update_sched_clock(&cd, ~__raw_readl(reg), (u32)~0);
> + return ~__raw_readl(reg);
> }
>
> static void __init s5p_clocksource_init(void)
> @@ -358,7 +335,7 @@ static void __init s5p_clocksource_init(void)
> s5p_time_setup(timer_source.source_id, TCNT_MAX);
> s5p_time_start(timer_source.source_id, PERIODIC);
>
> - init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate);
> + init_sched_clock(s5p_sched_clock_read, 32, clock_rate);
>
> if (clocksource_mmio_init(s5p_timer_reg(), "s5p_clocksource_timer",
> clock_rate, 250, 32, clocksource_mmio_readl_down))
> diff --git a/arch/arm/plat-versatile/sched-clock.c b/arch/arm/plat-versatile/sched-clock.c
> index 3d6a4c2..d9d5ba4 100644
> --- a/arch/arm/plat-versatile/sched-clock.c
> +++ b/arch/arm/plat-versatile/sched-clock.c
> @@ -24,35 +24,15 @@
> #include <asm/sched_clock.h>
> #include <plat/sched_clock.h>
>
> -static DEFINE_CLOCK_DATA(cd);
> static void __iomem *ctr;
>
> -/*
> - * Constants generated by clocks_calc_mult_shift(m, s, 24MHz, NSEC_PER_SEC, 60).
> - * This gives a resolution of about 41ns and a wrap period of about 178s.
> - */
> -#define SC_MULT 2796202667u
> -#define SC_SHIFT 26
> -
> -unsigned long long notrace sched_clock(void)
> -{
> - if (ctr) {
> - u32 cyc = readl(ctr);
> - return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0,
> - SC_MULT, SC_SHIFT);
> - } else
> - return 0;
> -}
> -
> -static void notrace versatile_update_sched_clock(void)
> +static u32 notrace versatile_sched_clock_read(void)
> {
> - u32 cyc = readl(ctr);
> - update_sched_clock(&cd, cyc, (u32)~0);
> + return readl(ctr);
> }
>
> void __init versatile_sched_clock_init(void __iomem *reg, unsigned long rate)
> {
> ctr = reg;
> - init_fixed_sched_clock(&cd, versatile_update_sched_clock,
> - 32, rate, SC_MULT, SC_SHIFT);
> + init_sched_clock(versatile_sched_clock_read, 32, rate);
> }
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* Identifying Primecells
From: jonsmirl at gmail.com @ 2011-09-22 18:19 UTC (permalink / raw)
To: linux-arm-kernel
I'm working on device tree support for the NXP LPC3130. To do this
right I need to know what specific Primecells were used in the chip.
How do I identify the primecell numbers for the devices? It is a
926ejs core.
--
Jon Smirl
jonsmirl at gmail.com
^ permalink raw reply
* [PATCH v2 1/3] TI81XX: Prepare for addition of TI814X support
From: Tony Lindgren @ 2011-09-22 18:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2A3DCF3DA181AD40BDE86A3150B27B6B03B4D17100@dbde02.ent.ti.com>
* Pedanekar, Hemant <hemantp@ti.com> [110921 17:00]:
> Tony Lindgren wrote on Thursday, September 22, 2011 2:11 AM:
>
> > * Hemant Pedanekar <hemantp@ti.com> [110921 10:05]:
> >> --- a/arch/arm/mach-omap2/board-ti8168evm.c
> >> +++ b/arch/arm/mach-omap2/board-ti8168evm.c
> >> @@ -37,16 +37,16 @@ static void __init ti8168_evm_init(void)
> >>
> >> static void __init ti8168_evm_map_io(void)
> >> {
> >> - omap2_set_globals_ti816x();
> >> - omapti816x_map_common_io();
> >> + omap2_set_globals_ti81xx();
> >> + omapti81xx_map_common_io();
> >> }
> >>
> >> MACHINE_START(TI8168EVM, "ti8168evm")
> >> /* Maintainer: Texas Instruments */
> >> .atag_offset = 0x100,
> >> .map_io = ti8168_evm_map_io,
> >> - .init_early = ti816x_init_early,
> >> - .init_irq = ti816x_init_irq,
> >> + .init_early = ti81xx_init_early,
> >> + .init_irq = ti81xx_init_irq,
> >> .timer = &omap3_timer,
> >> .init_machine = ti8168_evm_init,
> >> MACHINE_END
> >
> > Looks like you still need a minor rebase on the current cleanup
> > branch as the ti8668_evm_map_io is no longer needed. The cleanup
> > branch already has Paul's CHIP_IS removal, so that should be trivial.
> >
>
> Tony,
> Can you please clarify? Do we not need ti8168_evm_map_io() for global data
> initianlization and io init? Or, as you mentioned in comment on 3/3 of the
> series, do you mean to rename this with ti81xx and move to common.c?
Yes just have a generic one in common.c should be enough. Sorry I thought
that was already done, but looks like it was only done for omap3_map_io.
> > Ideally the rename patch would be separate without any functional
> > changes, maybe you can move the changes and additions to the next patch?
> >
> > Tony
>
> If the above understanding is correct, then I will just have to rename+move
> ti8168_evm_map_io() so the change can still be in this patch, right? Or are
> You referring to any other part which should not be in this patch?
Yes it's OK to keep it in this patch.
Tony
^ permalink raw reply
* [PATCH V7 1/5] AHCI Add the AHCI SATA feature on the MX53 platforms
From: Anton Vorontsov @ 2011-09-22 18:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJNCFVLm=bUMvXq7acke7Bd_tiV+b1=HjVp37KwtYyGsZHa+OQ@mail.gmail.com>
Hi Richard,
On Wed, Sep 21, 2011 at 03:05:44PM +0800, Richard Zhu wrote:
> Hi Sascha:
> One proposal about how to convert the ahci driver to devicetree in future.
> ahci driver system can make a reference to the evolution of the sdhc driver.
You don't need to "convert" ahci driver to devicetree. IIRC,
the current ahci_platform driver should work almost* out of
the box with OF-enabled architectures, as OF subsystem
automatically populates memory and interrupt resources for
platform devices.
Someday you might need to implement OF-specific bindings
(e.g. get some property from the device tree and translate
it into port flags). When/if you'll need it, you can just
add it into the driver.
* Almost: you have to add of_match_table into 'struct
platform_driver ahci_driver'.
> * separate the ahci to ahci common codes, ahci-pci driver and
> ahci-platform driver.
Done. Long time ago, actually.
> * create kinds of ahci vendor's own ahci platform driver refer to the
> sdhci-xxx driver solutions.
I think that this is viable, but personally I would like to
see platforms to just pass port flags and all needed hooks
via platform_data. That is, I'd leave the hooks in the arch/
code. Usually these hooks are very arch-specific (i.e. enable
these and these clocks, etc), so arch/ seems like a perfect
place for such things.
Not a strong opinion though, and if you like to go your route,
I'm also fine with this. It has its own pros (and cons).
Thanks,
--
Anton Vorontsov
Email: cbouatmailru at gmail.com
^ permalink raw reply
* [PATCH] ARM: futex: preserve oldval in SMP __futex_atomic_op
From: Will Deacon @ 2011-09-22 18:35 UTC (permalink / raw)
To: linux-arm-kernel
The SMP implementation of __futex_atomic_op clobbers oldval with the
status flag from the exclusive store. This causes it to always read as
zero when performing the FUTEX_OP_CMP_* operation.
This patch updates the ARM __futex_atomic_op implementations to take a
tmp argument, allowing us to store the strex status flag without
overwriting the register containing oldval.
Cc: stable at kernel.org
Reported-by: Minho Ben <mhban@samsung.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
Following up on:
http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/066348.html
it turns out that we don't need to use named arguments after all,
although it might be nice to add that as a later patch. For now, I'm
trying to keep this as small as possible for -stable.
arch/arm/include/asm/futex.h | 34 +++++++++++++++++-----------------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 8c73900..253cc86 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -25,17 +25,17 @@
#ifdef CONFIG_SMP
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
smp_mb(); \
__asm__ __volatile__( \
- "1: ldrex %1, [%2]\n" \
+ "1: ldrex %1, [%3]\n" \
" " insn "\n" \
- "2: strex %1, %0, [%2]\n" \
- " teq %1, #0\n" \
+ "2: strex %2, %0, [%3]\n" \
+ " teq %2, #0\n" \
" bne 1b\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
#include <linux/preempt.h>
#include <asm/domain.h>
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
__asm__ __volatile__( \
- "1: " T(ldr) " %1, [%2]\n" \
+ "1: " T(ldr) " %1, [%3]\n" \
" " insn "\n" \
- "2: " T(str) " %0, [%2]\n" \
+ "2: " T(str) " %0, [%3]\n" \
" mov %0, #0\n" \
- __futex_atomic_ex_table("%4") \
- : "=&r" (ret), "=&r" (oldval) \
+ __futex_atomic_ex_table("%5") \
+ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
@@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
int cmp = (encoded_op >> 24) & 15;
int oparg = (encoded_op << 8) >> 20;
int cmparg = (encoded_op << 20) >> 20;
- int oldval = 0, ret;
+ int oldval = 0, ret, tmp;
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg;
@@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
switch (op) {
case FUTEX_OP_SET:
- __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ADD:
- __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_OR:
- __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
case FUTEX_OP_ANDN:
- __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
+ __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
break;
case FUTEX_OP_XOR:
- __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
+ __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
break;
default:
ret = -ENOSYS;
--
1.7.0.4
^ permalink raw reply related
* [RFC PATCH v3] drivercore: Add driver probe deferral mechanism
From: Grant Likely @ 2011-09-22 18:51 UTC (permalink / raw)
To: linux-arm-kernel
Allow drivers to report at probe time that they cannot get all the resources
required by the device, and should be retried at a later time.
This should completely solve the problem of getting devices
initialized in the right order. Right now this is mostly handled by
mucking about with initcall ordering which is a complete hack, and
doesn't even remotely handle the case where device drivers are in
modules. This approach completely sidesteps the issues by allowing
driver registration to occur in any order, and any driver can request
to be retried after a few more other drivers get probed.
v3: - Hold off workqueue scheduling until late_initcall so that the bulk
of driver probes are complete before we start retrying deferred devices.
- Tested with simple use cases. Still needs more testing though.
Using it to get rid of the gpio early_initcall madness, or to replace
the ASoC internal probe deferral code would be ideal.
v2: - added locking so it should no longer be utterly broken in that regard
- remove device from deferred list at device_del time.
- Still completely untested with any real use case, but has been
boot tested.
TODO: - Create a separate singlethread_workqueue so that drivers can't
mess things up by calling flush_work().
- Maybe this should be wrapped with a kconfig symbol so it can
be compiled out on systems that don't care.
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Cc: Greg Kroah-Hartman <greg@kroah.com>
Cc: Mark Brown <broonie@opensource.wolfsonmicro.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dilan Lee <dilee@nvidia.com>
Cc: Manjunath GKondaiah <manjunath.gkondaiah@linaro.org>
---
Hi Manjunath,
Here's the current state of the patch. The major think that needs to
be done is to convert it to use a separate workqueue as described in
the TODO above. It also needs some users adapted to it. One of the
gpio drivers would work; preferably one of the newer drivers that
doesn't have a lot of drivers depending on the early_initcall()
behaviour yet.
Mark Brown may also be able to suggest specific examples.
For everyone else; this is the current state of the patch. I think it
is in pretty good shape other than the TODO item above. I'm turning
it over to Manjunath to polish up for merging. I would appreciate
any feedback.
g.
drivers/base/base.h | 1
drivers/base/core.c | 2 +
drivers/base/dd.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/device.h | 5 ++
4 files changed, 141 insertions(+), 1 deletions(-)
diff --git a/drivers/base/base.h b/drivers/base/base.h
index a34dca0..9641309 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -105,6 +105,7 @@ extern void bus_remove_driver(struct device_driver *drv);
extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
+extern void driver_deferred_probe_del(struct device *dev);
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bc8729d..0d37e18 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -588,6 +588,7 @@ void device_initialize(struct device *dev)
{
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
+ INIT_LIST_HEAD(&dev->deferred_probe);
INIT_LIST_HEAD(&dev->dma_pools);
mutex_init(&dev->mutex);
lockdep_set_novalidate_class(&dev->mutex);
@@ -1119,6 +1120,7 @@ void device_del(struct device *dev)
device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
bus_remove_device(dev);
+ driver_deferred_probe_del(dev);
/*
* Some platform devices are driven without driver attached
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6658da7..8be5b33 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -28,6 +28,129 @@
#include "base.h"
#include "power/power.h"
+/*
+ * Deferred Probe infrastructure.
+ *
+ * Sometimes driver probe order matters, but the kernel doesn't always have
+ * dependency information which means some drivers will get probed before a
+ * resource it depends on is available. For example, an SDHCI driver may
+ * first need a GPIO line from an i2c GPIO controller before it can be
+ * initialized. If a required resource is not available yet, a driver can
+ * request probing to be deferred by returning -EAGAIN from its probe hook
+ *
+ * Deferred probe maintains two lists of devices, a pending list and an active
+ * list. A driver returning -EAGAIN causes the device to be added to the
+ * pending list.
+ *
+ * The deferred_probe_mutex *must* be held any time the deferred_probe_*_list
+ * of the (struct device*)->deferred_probe pointers are manipulated
+ */
+static DEFINE_MUTEX(deferred_probe_mutex);
+static LIST_HEAD(deferred_probe_pending_list);
+static LIST_HEAD(deferred_probe_active_list);
+
+/**
+ * deferred_probe_work_func() - Retry probing devices in the active list.
+ */
+static void deferred_probe_work_func(struct work_struct *work)
+{
+ struct device *dev;
+ /*
+ * This bit is tricky. We want to process every device in the
+ * deferred list, but devices can be removed from the list at any
+ * time while inside this for-each loop. There are two things that
+ * need to be protected against:
+ * - if the device is removed from the deferred_probe_list, then we
+ * loose our place in the loop. Since any device can be removed
+ * asynchronously, list_for_each_entry_safe() wouldn't make things
+ * much better. Simplest solution is to restart walking the list
+ * whenever the current device gets removed. Not the most efficient,
+ * but is simple to implement and easy to audit for correctness.
+ * - if the device is unregistered, and freed, then there is a risk
+ * of a null pointer dereference. This code uses get/put_device()
+ * to ensure the device cannot disappear from under our feet.
+ */
+ mutex_lock(&deferred_probe_mutex);
+ while (!list_empty(&deferred_probe_active_list)) {
+ dev = list_first_entry(&deferred_probe_active_list,
+ typeof(*dev), deferred_probe);
+ list_del_init(&dev->deferred_probe);
+
+ get_device(dev);
+
+ /* Drop the mutex while probing each device; the probe path
+ * may manipulate the deferred list */
+ mutex_unlock(&deferred_probe_mutex);
+ dev_dbg(dev, "Retrying from deferred list\n");
+ bus_probe_device(dev);
+ mutex_lock(&deferred_probe_mutex);
+
+ put_device(dev);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
+
+static void driver_deferred_probe_add(struct device *dev)
+{
+ mutex_lock(&deferred_probe_mutex);
+ if (list_empty(&dev->deferred_probe)) {
+ dev_dbg(dev, "Added to deferred list\n");
+ list_add(&dev->deferred_probe, &deferred_probe_pending_list);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+
+void driver_deferred_probe_del(struct device *dev)
+{
+ mutex_lock(&deferred_probe_mutex);
+ if (!list_empty(&dev->deferred_probe)) {
+ dev_dbg(dev, "Removed from deferred list\n");
+ list_del_init(&dev->deferred_probe);
+ }
+ mutex_unlock(&deferred_probe_mutex);
+}
+
+static bool driver_deferred_probe_enable = false;
+/**
+ * driver_deferred_probe_trigger() - Kick off re-probing deferred devices
+ *
+ * This functions moves all devices from the pending list to the active
+ * list and schedules the deferred probe workqueue to process them. It
+ * should be called anytime a driver is successfully bound to a device.
+ */
+static void driver_deferred_probe_trigger(void)
+{
+ if (!driver_deferred_probe_enable)
+ return;
+
+ /* A successful probe means that all the devices in the pending list
+ * should be triggered to be reprobed. Move all the deferred devices
+ * into the active list so they can be retried by the workqueue */
+ mutex_lock(&deferred_probe_mutex);
+ list_splice_tail_init(&deferred_probe_pending_list,
+ &deferred_probe_active_list);
+ mutex_unlock(&deferred_probe_mutex);
+
+ /* Kick the re-probe thread. It may already be scheduled, but
+ * it is safe to kick it again. */
+ schedule_work(&deferred_probe_work);
+}
+
+/**
+ * deferred_probe_initcall() - Enable probing of deferred devices
+ *
+ * We don't want to get in the way when the bulk of drivers are getting probed.
+ * Instead, this initcall makes sure that deferred probing is delayed until
+ * late_initcall time.
+ */
+static int deferred_probe_initcall(void)
+{
+ driver_deferred_probe_enable = true;
+ driver_deferred_probe_trigger();
+ return 0;
+}
+late_initcall(deferred_probe_initcall);
static void driver_bound(struct device *dev)
{
@@ -42,6 +165,11 @@ static void driver_bound(struct device *dev)
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
+ /* Make sure the device is no longer in one of the deferred lists
+ * and kick off retrying all pending devices */
+ driver_deferred_probe_del(dev);
+ driver_deferred_probe_trigger();
+
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
@@ -142,7 +270,11 @@ probe_failed:
driver_sysfs_remove(dev);
dev->driver = NULL;
- if (ret != -ENODEV && ret != -ENXIO) {
+ if (ret == -EAGAIN) {
+ /* Driver requested deferred probing */
+ dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
+ driver_deferred_probe_add(dev);
+ } else if (ret != -ENODEV && ret != -ENXIO) {
/* driver matched but the probe failed */
printk(KERN_WARNING
"%s: probe of %s failed with error %d\n",
diff --git a/include/linux/device.h b/include/linux/device.h
index c20dfbf..dab93a4 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -506,6 +506,10 @@ struct device_dma_parameters {
* @mutex: Mutex to synchronize calls to its driver.
* @bus: Type of bus device is on.
* @driver: Which driver has allocated this
+ * @deferred_probe: entry in deferred_probe_list which is used to retry the
+ * binding of drivers which were unable to get all the resources
+ * needed by the device; typically because it depends on another
+ * driver getting probed first.
* @platform_data: Platform data specific to the device.
* Example: For devices on custom boards, as typical of embedded
* and SOC based hardware, Linux often uses platform_data to point
@@ -564,6 +568,7 @@ struct device {
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
+ struct list_head deferred_probe;
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
^ permalink raw reply related
* [RFC PATCH v3] drivercore: Add driver probe deferral mechanism
From: Joe Perches @ 2011-09-22 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20110922184614.25419.84606.stgit@ponder>
On Thu, 2011-09-22 at 12:51 -0600, Grant Likely wrote:
> Allow drivers to report at probe time that they cannot get all the resources
> required by the device, and should be retried at a later time.
[]
> I would appreciate
> any feedback.
trivia:
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
[]
> +static void driver_deferred_probe_add(struct device *dev)
> +{
> + mutex_lock(&deferred_probe_mutex);
> + if (list_empty(&dev->deferred_probe)) {
> + dev_dbg(dev, "Added to deferred list\n");
These messages might be more intelligible as
"Added to deferred probe list\n"
> +void driver_deferred_probe_del(struct device *dev)
> +{
> + mutex_lock(&deferred_probe_mutex);
> + if (!list_empty(&dev->deferred_probe)) {
> + dev_dbg(dev, "Removed from deferred list\n");
"Removed from deferred probe list\n"
^ permalink raw reply
* [PATCH] ARM: futex: preserve oldval in SMP __futex_atomic_op
From: Nicolas Pitre @ 2011-09-22 19:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1316716500-25376-1-git-send-email-will.deacon@arm.com>
On Thu, 22 Sep 2011, Will Deacon wrote:
> The SMP implementation of __futex_atomic_op clobbers oldval with the
> status flag from the exclusive store. This causes it to always read as
> zero when performing the FUTEX_OP_CMP_* operation.
>
> This patch updates the ARM __futex_atomic_op implementations to take a
> tmp argument, allowing us to store the strex status flag without
> overwriting the register containing oldval.
>
> Cc: stable at kernel.org
> Reported-by: Minho Ben <mhban@samsung.com>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
> ---
>
> Following up on:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/066348.html
>
> it turns out that we don't need to use named arguments after all,
> although it might be nice to add that as a later patch. For now, I'm
> trying to keep this as small as possible for -stable.
Agreed that named arguments would make this code more obvious,
especially with the insn argument of __futex_atomic_op() which uses
numbered registers away from the actual inline asm statement where it is
used.
I'm a bit worried that the LTP tests still passed though. In theory it
shouldn't have worked at all except if you were lucky with test values.
>
> arch/arm/include/asm/futex.h | 34 +++++++++++++++++-----------------
> 1 files changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
> index 8c73900..253cc86 100644
> --- a/arch/arm/include/asm/futex.h
> +++ b/arch/arm/include/asm/futex.h
> @@ -25,17 +25,17 @@
>
> #ifdef CONFIG_SMP
>
> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
> +#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
> smp_mb(); \
> __asm__ __volatile__( \
> - "1: ldrex %1, [%2]\n" \
> + "1: ldrex %1, [%3]\n" \
> " " insn "\n" \
> - "2: strex %1, %0, [%2]\n" \
> - " teq %1, #0\n" \
> + "2: strex %2, %0, [%3]\n" \
> + " teq %2, #0\n" \
> " bne 1b\n" \
> " mov %0, #0\n" \
> - __futex_atomic_ex_table("%4") \
> - : "=&r" (ret), "=&r" (oldval) \
> + __futex_atomic_ex_table("%5") \
> + : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
> : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
> : "cc", "memory")
>
> @@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
> #include <linux/preempt.h>
> #include <asm/domain.h>
>
> -#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
> +#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
> __asm__ __volatile__( \
> - "1: " T(ldr) " %1, [%2]\n" \
> + "1: " T(ldr) " %1, [%3]\n" \
> " " insn "\n" \
> - "2: " T(str) " %0, [%2]\n" \
> + "2: " T(str) " %0, [%3]\n" \
> " mov %0, #0\n" \
> - __futex_atomic_ex_table("%4") \
> - : "=&r" (ret), "=&r" (oldval) \
> + __futex_atomic_ex_table("%5") \
> + : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
> : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
> : "cc", "memory")
>
> @@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
> int cmp = (encoded_op >> 24) & 15;
> int oparg = (encoded_op << 8) >> 20;
> int cmparg = (encoded_op << 20) >> 20;
> - int oldval = 0, ret;
> + int oldval = 0, ret, tmp;
>
> if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
> oparg = 1 << oparg;
> @@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
>
> switch (op) {
> case FUTEX_OP_SET:
> - __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_ADD:
> - __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_OR:
> - __futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> case FUTEX_OP_ANDN:
> - __futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
> + __futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
> break;
> case FUTEX_OP_XOR:
> - __futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
> + __futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
> break;
> default:
> ret = -ENOSYS;
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ 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