* [PATCH v3 04/11] ARM: Exynos4: Migrate clock support to common clock framework
From: Thomas Abraham @ 2012-11-15 9:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1496911.LC6ynRgIgc@flatron>
On 15 November 2012 05:01, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> On Thursday 15 of November 2012 03:37:26 Thomas Abraham wrote:
>> Remove Samsung specific clock support in Exynos4 and migrate to use
>> common clock framework.
>>
>> Cc: Kukjin Kim <kgene.kim@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>> arch/arm/mach-exynos/Kconfig | 1 +
>> arch/arm/mach-exynos/Makefile | 3 -
>> arch/arm/mach-exynos/clock-exynos4.c | 1602
>> ---------------------------- arch/arm/mach-exynos/clock-exynos4.h
>> | 35 -
>> arch/arm/mach-exynos/clock-exynos4210.c | 188 ----
>> arch/arm/mach-exynos/clock-exynos4212.c | 192 ----
>> arch/arm/mach-exynos/common.c | 22 +-
>> arch/arm/mach-exynos/common.h | 3 +
>> arch/arm/mach-exynos/mach-armlex4210.c | 1 -
>> arch/arm/mach-exynos/mach-exynos4-dt.c | 1 -
>> arch/arm/mach-exynos/mach-nuri.c | 1 -
>> arch/arm/mach-exynos/mach-origen.c | 1 -
>> arch/arm/mach-exynos/mach-smdk4x12.c | 1 -
>> arch/arm/mach-exynos/mach-smdkv310.c | 1 -
>> arch/arm/mach-exynos/mach-universal_c210.c | 1 -
>> arch/arm/mach-exynos/mct.c | 19 +
>> arch/arm/plat-samsung/Kconfig | 4 +-
>> 17 files changed, 27 insertions(+), 2049 deletions(-)
>> delete mode 100644 arch/arm/mach-exynos/clock-exynos4.c
>> delete mode 100644 arch/arm/mach-exynos/clock-exynos4.h
>> delete mode 100644 arch/arm/mach-exynos/clock-exynos4210.c
>> delete mode 100644 arch/arm/mach-exynos/clock-exynos4212.c
>>
> [snip]
>> diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
>> index f7792b8..c2e806c 100644
>> --- a/arch/arm/mach-exynos/mct.c
>> +++ b/arch/arm/mach-exynos/mct.c
>> @@ -31,6 +31,7 @@
>> #include <mach/map.h>
>> #include <mach/irqs.h>
>> #include <asm/mach/time.h>
>> +#include "common.h"
>>
>> #define EXYNOS4_MCTREG(x) (x)
>> #define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100)
>> @@ -517,6 +518,24 @@ static void __init exynos4_timer_init(void)
>> struct device_node *np;
>> u32 nr_irqs, i;
>>
>> +#ifdef CONFIG_COMMON_CLK
>> + /*
>> + * Clock lookup should be functional now since the MCT controller
>> driver + * looks up clocks. So the clock initialization is initiated
>> here. + */
>> + if (of_have_populated_dt()) {
>> + if (of_machine_is_compatible("samsung,exynos4210") ||
>> + of_machine_is_compatible("samsung,exynos4212") ||
>> + of_machine_is_compatible("samsung,exynos4412"))
>> + exynos4_clk_init();
>> + } else {
>> + if (soc_is_exynos4210() || soc_is_exynos4212() ||
>> + soc_is_exynos4412()) {
>> + exynos4_clk_init();
>> + }
>> + }
>> +#endif
>> +
>
> I don't like the idea of initializing the clocks from timer
> initialization. What about some platforms where MCT isn't used? It is also
> far from being elegant.
Very true, I did also prefer not do this. But, clock lookup should be
functional atleast by the time mct initialization begins. So I tried
few options such as adding .early_init_call callback in MACHINE_DESC
which then can call exynos4_clk_init, but that did not help since
mem_init isn't complete by then and memory allocation failed during
clock registration. Other methods also did not help much. If you know
of a solution to get around this, could you please let me know.
Thanks,
Thomas.
^ permalink raw reply
* [PATCH] ARM: add get_user() support for 8 byte types
From: Arnd Bergmann @ 2012-11-15 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121113112430.GF28341@n2100.arm.linux.org.uk>
On Tuesday 13 November 2012, Russell King - ARM Linux wrote:
> You're missing something; that is one of the greatest powers of open
> source. The many eyes (and minds) effect. Someone out there probably
> has a solution to whatever problem, the trick is to find that person. :)
>
> I think we have a working solution for this for ARM. It won't be suitable
> for every arch, where they have 8-bit and 16-bit registers able to be
> allocated by the compiler, but for architectures where the minimum register
> size is 32-bit, what we have below should work.
I don't mind at all adding the extension to ARM, and I think it's pretty
cool that you guys actually found a working solution.
The part that worries me is that we are making architecture independent
code depend on a clever hack that may or may not be possible to implement
on a given architecture, and that most architecture maintainers wouldn't
know how to implement correctly even if it's possible.
Arnd
^ permalink raw reply
* [PATCH] ARM: Fix errata 751472 handling on Cortex-A9 r1p*
From: Russell King - ARM Linux @ 2012-11-15 9:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121114222159.GB6801@atomide.com>
On Wed, Nov 14, 2012 at 02:21:59PM -0800, Tony Lindgren wrote:
> No idea if assuming that zero value for the diagnostic register
> is safe.. What's the default value of the diagnostic register supposed
> to be?
No, that's not safe. What if your pre-kernel code has asked the secure
monitor to set the work-around bit already?
> #if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
> ALT_SMP(cmp r6, #0x30) @ present prior to r3p0
> ALT_UP_B(1f)
> - mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register
> - orrlt r10, r10, #1 << 11 @ set bit #11
> - mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
> + bge 1f @ not needed for r3p0 and later
> + mrc p15, 0, r10, c15, c0, 1 @ read diagnostic register
> + teq r10, #0 @ zero for secure mode?
> + beq 1f @ bail out for secure mode
This test for zero is pointless. What if some other work-around has
been enabled but not this one?
> + tst r10, #1 << 11 @ bit #11 already set?
> + orreq r10, r10, #1 << 11 @ set bit #11 if not set
> + mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
> 1:
> #endif
>
^ permalink raw reply
* [PATCH v3 07/11] ARM: Exynos4: allow legacy board support to specify xxti and xusbxti clock speed
From: Thomas Abraham @ 2012-11-15 9:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7438966.1DHnOH3JLs@flatron>
On 15 November 2012 05:06, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> On Thursday 15 of November 2012 03:37:29 Thomas Abraham wrote:
>> The clock speed of xxti and xusbxti clocks depends on the oscillator
>> used on the board to generate these clocks. For non-dt platforms, allow
>> the board support for those platforms to set the clock frequency of
>> xxti and xusbxti clocks.
>>
>> Cc: Kukjin Kim <kgene.kim@samsung.com>
>> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
>> ---
>> arch/arm/mach-exynos/common.c | 2 ++
>> arch/arm/mach-exynos/common.h | 1 +
>> arch/arm/mach-exynos/mach-nuri.c | 2 ++
>> arch/arm/mach-exynos/mach-origen.c | 2 ++
>> arch/arm/mach-exynos/mach-smdkv310.c | 2 ++
>> arch/arm/mach-exynos/mach-universal_c210.c | 2 ++
>> arch/arm/mach-exynos/mct.c | 1 +
>> 7 files changed, 12 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-exynos/common.c
>> b/arch/arm/mach-exynos/common.c index 138a41d..64c0012 100644
>> --- a/arch/arm/mach-exynos/common.c
>> +++ b/arch/arm/mach-exynos/common.c
>> @@ -65,6 +65,8 @@ static void exynos5_init_clocks(int xtal);
>> static void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no);
>> static int exynos_init(void);
>>
>> +unsigned long xxti_f = 0, xusbxti_f = 0;
>> +
>> static struct cpu_table cpu_ids[] __initdata = {
>> {
>> .idcode = EXYNOS4210_CPU_ID,
>> diff --git a/arch/arm/mach-exynos/common.h
>> b/arch/arm/mach-exynos/common.h index 2cacd48..f947789 100644
>> --- a/arch/arm/mach-exynos/common.h
>> +++ b/arch/arm/mach-exynos/common.h
>> @@ -22,6 +22,7 @@ void exynos4_restart(char mode, const char *cmd);
>> void exynos5_restart(char mode, const char *cmd);
>> void exynos_init_late(void);
>>
>> +extern unsigned long xxti_f, xusbxti_f;
>> void exynos4_clk_init(void);
>> void exynos4_clk_register_fixed_ext(unsigned long, unsigned long);
>>
>> diff --git a/arch/arm/mach-exynos/mach-nuri.c
>> b/arch/arm/mach-exynos/mach-nuri.c index 5b5c941..e14332c 100644
>> --- a/arch/arm/mach-exynos/mach-nuri.c
>> +++ b/arch/arm/mach-exynos/mach-nuri.c
>> @@ -1332,6 +1332,8 @@ static void __init nuri_map_io(void)
>> {
>> exynos_init_io(NULL, 0);
>> s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs));
>> + xxti_f = 0;
>> + xusbxti_f = 24000000;
>
> I don't like setting these variables directly from board code.
>
> If you didn't remove clock initialization call from board code, you could
> extend that function to take these two frequencies as arguments?
Right, but I was not in favour of changing the s3c24xx_init_clocks()
api since that would mean all board code calling this will require
updates. So I was contemplating of adding a new exynos4 specific api.
But then did not opt for it, knowing very well that it is just a
matter of time before we add dt support to existing non-dt exynos4
board files. So just to keep things functional for now, and not add to
much of non-dt stuff, I did this.
>
>> }
>>
>> static void __init nuri_reserve(void)
> [snip]
>> diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
>> index c2e806c..cd061b2 100644
>> --- a/arch/arm/mach-exynos/mct.c
>> +++ b/arch/arm/mach-exynos/mct.c
>> @@ -532,6 +532,7 @@ static void __init exynos4_timer_init(void)
>> if (soc_is_exynos4210() || soc_is_exynos4212() ||
>> soc_is_exynos4412()) {
>> exynos4_clk_init();
>> + exynos4_clk_register_fixed_ext(xxti_f, xusbxti_f);
>
> I don't like registering clocks from unrelated code. IMHO any clock
> registration should be done from code in drivers/clk/samsung.
Ok. I will check for other alternatives.
Thanks,
Thomas.
^ permalink raw reply
* Fwd: [PATCH 1/7] I2c-nomadik: Fix the usage of wait_for_completion_timeout
From: Wolfram Sang @ 2012-11-15 9:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121115084858.GA29668@bnru10>
> > - if (timeout < 0) {
> > - dev_err(&dev->adev->dev,
> > - "wait_for_completion_timeout "
> > - "returned %d waiting for event\n", timeout);
> > - status = timeout;
> > - }
> > -
> No, it is wrong. You need to update the status variable in the case of timeout.
Looking at the patch context, such code comes later.
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121115/f7edc23a/attachment.sig>
^ permalink raw reply
* [PATCH v4] linux,stdout-path helper
From: Sascha Hauer @ 2012-11-15 9:31 UTC (permalink / raw)
To: linux-arm-kernel
The following adds a helper for matching the linux,stdout-path property
in the chosen node and makes use of it in the i.MX serial driver.
changes since v3:
- move code from separate files to drivers/of/base.c and include/linux/of.h
changes since v2:
- move helper to OF core and make it independent of serial devices
changes since v1:
- move it out of the i.MX serial driver and make it generic for serial
devices.
^ permalink raw reply
* [PATCH 1/3] OF: Add helper for matching against linux,stdout-path
From: Sascha Hauer @ 2012-11-15 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352971866-540-1-git-send-email-s.hauer@pengutronix.de>
devicetrees may have a linux,stdout-path property in the chosen
node describing the console device. This adds a helper function
to match a device against this property so a driver can call
add_preferred_console for a matching device.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/of/base.c | 28 ++++++++++++++++++++++++++++
include/linux/of.h | 7 +++++++
2 files changed, 35 insertions(+)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index af3b22a..737feb8 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1358,3 +1358,31 @@ const char *of_prop_next_string(struct property *prop, const char *cur)
return curv;
}
EXPORT_SYMBOL_GPL(of_prop_next_string);
+
+/**
+ * of_device_is_stdout_path - check if a device node matches the
+ * linux,stdout-path property
+ *
+ * Check if this device node matches the linux,stdout-path property
+ * in the chosen node. return true if yes, false otherwise.
+ */
+int of_device_is_stdout_path(struct device_node *dn)
+{
+ const char *name;
+ struct device_node *dn_stdout;
+ int is_stdout = 0;
+
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL)
+ return 0;
+
+ dn_stdout = of_find_node_by_path(name);
+
+ if (dn_stdout && dn_stdout == dn)
+ is_stdout = 1;
+
+ of_node_put(dn_stdout);
+
+ return is_stdout;
+}
+EXPORT_SYMBOL_GPL(of_device_is_stdout_path);
diff --git a/include/linux/of.h b/include/linux/of.h
index b4e50d5..5f857b5 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -310,6 +310,8 @@ const char *of_prop_next_string(struct property *prop, const char *cur);
s; \
s = of_prop_next_string(prop, s))
+int of_device_is_stdout_path(struct device_node *dn);
+
#else /* CONFIG_OF */
static inline const char* of_node_full_name(struct device_node *np)
@@ -437,6 +439,11 @@ static inline int of_machine_is_compatible(const char *compat)
return 0;
}
+static inline int of_device_is_stdout_path(struct device_node *dn)
+{
+ return 0;
+}
+
#define of_match_ptr(_ptr) NULL
#define of_match_node(_matches, _node) NULL
#define of_property_for_each_u32(np, propname, prop, p, u) \
--
1.7.10.4
^ permalink raw reply related
* [PATCH 2/3] serial: i.MX: Make console support non optional
From: Sascha Hauer @ 2012-11-15 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352971866-540-1-git-send-email-s.hauer@pengutronix.de>
Traditionally console support is optional for serial drivers. This
makes it non optional for the i.MX driver since it's not worth
asking questions for a feature virtually every user of this driver
wants to have.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/tty/serial/Kconfig | 16 +---------------
drivers/tty/serial/imx.c | 8 +-------
2 files changed, 2 insertions(+), 22 deletions(-)
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2a53be5..919b243 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -541,26 +541,12 @@ config SERIAL_IMX
bool "IMX serial port support"
depends on ARCH_MXC
select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
select RATIONAL
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
-config SERIAL_IMX_CONSOLE
- bool "Console on IMX serial port"
- depends on SERIAL_IMX
- select SERIAL_CORE_CONSOLE
- help
- If you have enabled the serial port on the Motorola IMX
- CPU you can make it the console by answering Y to this option.
-
- Even if you say Y here, the currently visible virtual console
- (/dev/tty0) will still be used as the system console by default, but
- you can alter that using a kernel command line option such as
- "console=ttySA0". (Try "man bootparam" or see the documentation of
- your boot loader (lilo or loadlin) about how to pass options to the
- kernel at boot time.)
-
config SERIAL_UARTLITE
tristate "Xilinx uartlite serial port support"
depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 5981912..07a8ca1 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1192,7 +1192,6 @@ static struct uart_ops imx_pops = {
static struct imx_port *imx_ports[UART_NR];
-#ifdef CONFIG_SERIAL_IMX_CONSOLE
static void imx_console_putchar(struct uart_port *port, int ch)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -1348,11 +1347,6 @@ static struct console imx_console = {
.data = &imx_reg,
};
-#define IMX_CONSOLE &imx_console
-#else
-#define IMX_CONSOLE NULL
-#endif
-
static struct uart_driver imx_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
@@ -1360,7 +1354,7 @@ static struct uart_driver imx_reg = {
.major = SERIAL_IMX_MAJOR,
.minor = MINOR_START,
.nr = ARRAY_SIZE(imx_ports),
- .cons = IMX_CONSOLE,
+ .cons = &imx_console,
};
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
--
1.7.10.4
^ permalink raw reply related
* [PATCH 3/3] serial: i.MX: evaluate linux,stdout-path property
From: Sascha Hauer @ 2012-11-15 9:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352971866-540-1-git-send-email-s.hauer@pengutronix.de>
devicetrees may have the linux,stdout-path property to specify the
console. This patch adds support to the i.MX serial driver for this.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/tty/serial/imx.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 07a8ca1..ac5a679 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1419,6 +1419,9 @@ static int serial_imx_probe_dt(struct imx_port *sport,
sport->devdata = of_id->data;
+ if (of_device_is_stdout_path(np))
+ add_preferred_console(imx_reg.cons->name, sport->port.line, 0);
+
return 0;
}
#else
--
1.7.10.4
^ permalink raw reply related
* Kernel uncompression error
From: Russell King - ARM Linux @ 2012-11-15 9:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50A4841F.9070507@gmail.com>
On Thu, Nov 15, 2012 at 01:56:47PM +0800, woody wrote:
> On 11/15/2012 1:34 AM, Russell King - ARM Linux wrote:
>> On Wed, Nov 14, 2012 at 10:23:55PM +0800, woody wrote:
>>> I just built a 3.2.x ARM kernel and tried to have it boot by a boot
>>> loader (vivi) on my s3c2410a ARM board. The kernel was built with
>>> default configuration s3c2410.
>>
>> I reported that S3C2410 is totally dead with 3.x kernels about a month
>> ago and got no response what so ever from anyone. I guess S3C2410 is
>> just not cared for anymore.
>>
>> When I get sufficient motivation, I'll try and track down what's going
>> wrong, but it means taking the old mailing list server (and now list
>> archive) offline for a while.
>>
>> I don't think it's cache related; different image sizes seem to behave
>> differently - and when they _do_ successfully decompress, they don't
>> boot at all.
>
> Now I switched from 3.2.x kernel to the latest stable 3.6.6. And, I did
> a lot of configuration to make the zImage size smaller, now it is 1.5M.
> After download it to the board, I got another error:
>
> "Uncompressing Linux... done, booting the kernel."
>
> Then the kernel halted.
>
> I noticed, the dots (...) in the kernel log seems very short, is this a
> clue or just normal?
You've not told me anything I don't already know... As I said, it needs
investigation as to what's going on. I was rather hoping that the Samsung
people would look at it, but alas there seems to be zero interest from
them.
As for the shorter dots, that's normal now with the multi-format
decompressor.
^ permalink raw reply
* Kernel uncompression error
From: Russell King - ARM Linux @ 2012-11-15 9:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAAsE_ufdjZN31BXWTcq5XyRhx5YcoECRJVvARcNh8qT-AP1_jw@mail.gmail.com>
On Thu, Nov 15, 2012 at 07:35:30AM +0800, Woody Wu wrote:
> ? 2012-11-15 AM1:34?"Russell King - ARM Linux" <linux@arm.linux.org.uk>???
> >
> > On Wed, Nov 14, 2012 at 10:23:55PM +0800, woody wrote:
> > > I just built a 3.2.x ARM kernel and tried to have it boot by a boot
> > > loader (vivi) on my s3c2410a ARM board. The kernel was built with
> > > default configuration s3c2410.
> >
> > I reported that S3C2410 is totally dead with 3.x kernels about a month
> > ago and got no response what so ever from anyone. I guess S3C2410 is
> > just not cared for anymore.
> >
> > When I get sufficient motivation, I'll try and track down what's going
> > wrong, but it means taking the old mailing list server (and now list
> > archive) offline for a while.
> >
> > I don't think it's cache related; different image sizes seem to behave
> > differently - and when they _do_ successfully decompress, they don't
> > boot at all.
>
> So, in your opinion, what version of kernel I should go for s3c2410?
lists.arm.linux.org.uk currently runs 2.6.32.8. That's the last working
kernel I currently know of.
As I said, I tried several 3.x kernels, all of them failed.
^ permalink raw reply
* [PATCH 06/17] spi/atmel_spi: add flag to controller data for lock operations
From: Shubhrajyoti Datta @ 2012-11-15 9:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352710357-3265-7-git-send-email-wenyou.yang@atmel.com>
On Mon, Nov 12, 2012 at 2:22 PM, Wenyou Yang <wenyou.yang@atmel.com> wrote:
> From: Nicolas Ferre <nicolas.ferre@atmel.com>
>
> Will allow to drop the lock during DMA operations.
>
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> Cc: grant.likely at secretlab.ca
> Cc: spi-devel-general at lists.sourceforge.net
> ---
> drivers/spi/spi-atmel.c | 31 +++++++++++++++++++------------
> 1 file changed, 19 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
> index 76a1baf..37f54c3 100644
> --- a/drivers/spi/spi-atmel.c
> +++ b/drivers/spi/spi-atmel.c
> @@ -187,6 +187,7 @@
> */
> struct atmel_spi {
> spinlock_t lock;
> + unsigned long flags;
>
> resource_size_t phybase;
> void __iomem *regs;
> @@ -323,6 +324,16 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
> gpio_set_value(asd->npcs_pin, !active);
> }
>
> +static void atmel_spi_lock(struct atmel_spi *as)
> +{
> + spin_lock_irqsave(&as->lock, as->flags);
> +}
> +
> +static void atmel_spi_unlock(struct atmel_spi *as)
> +{
> + spin_unlock_irqrestore(&as->lock, as->flags);
> +}
May be this can be called directly.
> +
> static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
> struct spi_transfer *xfer)
> {
> @@ -559,9 +570,9 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
> "xfer complete: %u bytes transferred\n",
> msg->actual_length);
>
> - spin_unlock(&as->lock);
> + atmel_spi_unlock(as);
> msg->complete(msg->context);
> - spin_lock(&as->lock);
> + atmel_spi_lock(as);
>
> as->current_transfer = NULL;
> as->next_transfer = NULL;
> @@ -788,13 +799,11 @@ static int atmel_spi_setup(struct spi_device *spi)
> spi->controller_state = asd;
> gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
> } else {
> - unsigned long flags;
> -
> - spin_lock_irqsave(&as->lock, flags);
> + atmel_spi_lock(as);
> if (as->stay == spi)
> as->stay = NULL;
> cs_deactivate(as, spi);
> - spin_unlock_irqrestore(&as->lock, flags);
> + atmel_spi_unlock(as);
> }
>
> asd->csr = csr;
> @@ -813,7 +822,6 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
> {
> struct atmel_spi *as;
> struct spi_transfer *xfer;
> - unsigned long flags;
> struct device *controller = spi->master->dev.parent;
> u8 bits;
> struct atmel_spi_device *asd;
> @@ -878,11 +886,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
> msg->status = -EINPROGRESS;
> msg->actual_length = 0;
>
> - spin_lock_irqsave(&as->lock, flags);
> + atmel_spi_lock(as);
> list_add_tail(&msg->queue, &as->queue);
> if (!as->current_transfer)
> atmel_spi_next_message(spi->master);
> - spin_unlock_irqrestore(&as->lock, flags);
> + atmel_spi_unlock(as);
>
> return 0;
> }
> @@ -892,17 +900,16 @@ static void atmel_spi_cleanup(struct spi_device *spi)
> struct atmel_spi *as = spi_master_get_devdata(spi->master);
> struct atmel_spi_device *asd = spi->controller_state;
> unsigned gpio = (unsigned) spi->controller_data;
> - unsigned long flags;
>
> if (!asd)
> return;
>
> - spin_lock_irqsave(&as->lock, flags);
> + atmel_spi_lock(as);
> if (as->stay == spi) {
> as->stay = NULL;
> cs_deactivate(as, spi);
> }
> - spin_unlock_irqrestore(&as->lock, flags);
> + atmel_spi_unlock(as);
>
> spi->controller_state = NULL;
> gpio_free(gpio);
> --
> 1.7.9.5
>
>
> ------------------------------------------------------------------------------
> Everyone hates slow websites. So do we.
> Make your web apps faster with AppDynamics
> Download AppDynamics Lite for free today:
> http://p.sf.net/sfu/appdyn_d2d_nov
> _______________________________________________
> spi-devel-general mailing list
> spi-devel-general at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/spi-devel-general
^ permalink raw reply
* [PATCH v3 2/6] ARM: davinci: Changed pr_warning() to pr_warn() (part 2)
From: Sergei Shtylyov @ 2012-11-15 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <13514BD7FAEBA745BBD7D8A672905C14311F2D0E@DFLE08.ent.ti.com>
Hello.
On 15-11-2012 5:53, Tivy, Robert wrote:
>>> Also, while modifying those pr_warning() calls I changed hardcoded
>>> function names to use '"%s:", __func__' instead
>>> Signed-off-by: Robert Tivy <rtivy@ti.com>
>>> ---
>>> Clean up files that will be otherwise modified in subsequent patch.
>>> Applies to v3.7-rc2 tag (commit
>>> 6f0c0580b70c89094b3422ba81118c7b959c7556) of Linus' mainline kernel
>> at git.kernel.org.
>>> arch/arm/mach-davinci/board-omapl138-hawk.c | 30 ++++++++++------
>> -----------
>>> 1 file changed, 11 insertions(+), 19 deletions(-)
>> Taksing of separation of board and SoC specific changes, this patch
I meant "talking". :-/
>> shouldn't have been separated from patch 1 at all -- since it's two
>> boards built around the same chip, OMAP-L138...
> The 4 patches that are of the same nature ("Changed pr_warning() to pr_warn() (part #)") were split as 4 separate patches on request by Sekhar, for the purpose of making it easier to merge later.
To quote Sekhar: "My main motivation was to keep board and soc file
changes from mixing together." You just went too far.
WBR, Sergei
^ permalink raw reply
* Fwd: [PATCH 1/7] I2c-nomadik: Fix the usage of wait_for_completion_timeout
From: Srinidhi Kasagar @ 2012-11-15 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121115092953.GA418@pengutronix.de>
On Thu, Nov 15, 2012 at 10:29:53 +0100, Wolfram Sang wrote:
>
> > > - if (timeout < 0) {
> > > - dev_err(&dev->adev->dev,
> > > - "wait_for_completion_timeout "
> > > - "returned %d waiting for event\n", timeout);
> > > - status = timeout;
> > > - }
> > > -
> > No, it is wrong. You need to update the status variable in the case of timeout.
>
> Looking at the patch context, such code comes later.
But it causes regressions; without looking at the "later" code, we can't afford merging
this code now.
regards/srinidhi
^ permalink raw reply
* [PATCH RESEND 3/4] pinctrl: at91: Prevent NULL dereference if of_match_device returns NULL
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-15 10:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352955480.6793.8.camel@phoenix>
On 12:58 Thu 15 Nov , Axel Lin wrote:
> of_match_device() may return NULL.
this is not possible on at91
and I do a oups here as if we have a NULL pointer which means the driver is
wrong
Best Regards,
J.
>
> Signed-off-by: Axel Lin <axel.lin@ingics.com>
> ---
> This resend CC Jean-Christophe.
>
> drivers/pinctrl/pinctrl-at91.c | 17 +++++++++++++----
> 1 file changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
> index 8490a55..32006c8 100644
> --- a/drivers/pinctrl/pinctrl-at91.c
> +++ b/drivers/pinctrl/pinctrl-at91.c
> @@ -829,13 +829,18 @@ static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
> uint32_t *tmp;
> struct device_node *np = pdev->dev.of_node;
> struct device_node *child;
> + const struct of_device_id *match;
>
> if (!np)
> return -ENODEV;
>
> + match = of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
> + if (!match)
> + return -ENODEV;
> +
> info->dev = &pdev->dev;
> - info->ops = (struct at91_pinctrl_mux_ops*)
> - of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
> + info->ops = (struct at91_pinctrl_mux_ops *) match->data;
> +
> at91_pinctrl_child_count(info, np);
>
> if (info->nbanks < 1) {
> @@ -1359,6 +1364,7 @@ static struct of_device_id at91_gpio_of_match[] __devinitdata = {
> static int __devinit at91_gpio_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> + const struct of_device_id *match;
> struct resource *res;
> struct at91_gpio_chip *at91_chip = NULL;
> struct gpio_chip *chip;
> @@ -1399,8 +1405,11 @@ static int __devinit at91_gpio_probe(struct platform_device *pdev)
> goto err;
> }
>
> - at91_chip->ops = (struct at91_pinctrl_mux_ops*)
> - of_match_device(at91_gpio_of_match, &pdev->dev)->data;
> + match = of_match_device(at91_gpio_of_match, &pdev->dev);
> + if (!match)
> + return -ENODEV;
> +
> + at91_chip->ops = (struct at91_pinctrl_mux_ops *) match->data;
> at91_chip->pioc_virq = irq;
> at91_chip->pioc_idx = alias_idx;
>
> --
> 1.7.9.5
>
>
>
^ permalink raw reply
* [PATCH 0/2] Boottime: measure bootloader and kernel bootup time
From: Lee Jones @ 2012-11-15 10:04 UTC (permalink / raw)
To: linux-arm-kernel
This patchset supplies a new tool which measures boottime inclusive
of bootloader involvement. It seems to be accurate and adds no
latency to the booting of the system.
In the first round of testing we booted the kernel 3 times each with
boottime enabled and disabled. Actually, when it was disabled, the
code was completely removed from the kernel source and the kernel was
rebuilt. The difference between present & enabled and completely
removed was very little indeed. In fact, averaging out the 3 runs of
each, when boottime was enabled the system booted 4ms _faster_, go
figure!
Enabled Disabled
1st run 2.983093 2.985168
2nd run 2.973266 2.971801
3rd run 2.975402 2.987304
Average 2.977254 2.981424 -0.004171 (-4ms)
For the next round of testing, we delayed the bootloader for varying
amounts of time, then started to remove key components from kernel
functionality to see if the boottime system would pick-up on them.
/* Hang around in the bootloader for a while. */
$ cat /sys/kernel/debug/boottime/summary
kernel: 42864 msecs
total: 42864 msecs
kernel: cpu0 system: 56% idle: 43% iowait: 0% irq: 0%
cpu1 system: 4% idle: 95% iowait: 0% irq: 0%
/* Hang around in the bootloader for a smaller amount of time. */
kernel: 12351 msecs
total: 12351 msecs
kernel: cpu0 system: 56% idle: 43% iowait: 0% irq: 0%
cpu1 system: 2% idle: 97% iowait: 0% irq: 0%
/* Instant boot. (1st run) */
kernel: 7833 msecs
total: 7833 msecs
kernel: cpu0 system: 55% idle: 44% iowait: 0% irq: 0%
cpu1 system: 3% idle: 96% iowait: 0% irq: 0%
/* Instant boot. (2nd run) */
kernel: 7817 msecs
total: 7817 msecs
kernel: cpu0 system: 53% idle: 46% iowait: 0% irq: 0%
cpu1 system: 8% idle: 91% iowait: 0% irq: 0%
/* Instant boot. (3rd run) */
kernel: 7747 msecs
total: 7747 msecs
kernel: cpu0 system: 56% idle: 42% iowait: 0% irq: 0%
cpu1 system: 2% idle: 97% iowait: 0% irq: 0%
/* Instant boot. (4th run)
-CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_INPUT_TOUCHSCREEN is not set
*/
kernel: 7046 msecs
total: 7046 msecs
kernel: cpu0 system: 72% idle: 27% iowait: 0% irq: 0%
cpu1 system: 5% idle: 94% iowait: 0% irq: 0%
/* Instant boot. (5th run)
-CONFIG_MMC=y
+# CONFIG_MMC is not set
*/
kernel: 6778 msecs
total: 6778 msecs
kernel: cpu0 system: 81% idle: 18% iowait: 0% irq: 0%
cpu1 system: 1% idle: 98% iowait: 0% irq: 0%
arch/arm/common/Makefile | 1 +
arch/arm/common/boottime.c | 46 +++
arch/arm/include/uapi/asm/setup.h | 22 ++
drivers/clocksource/clksrc-dbx500-prcmu.c | 20 ++
include/linux/boottime.h | 89 ++++++
init/Kconfig | 9 +
init/Makefile | 1 +
init/boottime.c | 475 +++++++++++++++++++++++++++++
init/main.c | 6 +
9 files changed, 669 insertions(+)
^ permalink raw reply
* [PATCH 1/2] Boottime: A tool for automatic measurement of kernel/bootloader boot time
From: Lee Jones @ 2012-11-15 10:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352973847-21605-1-git-send-email-lee.jones@linaro.org>
The overhead is very low and the results will be found under
sysfs/bootime, as well as detailed results in debugfs under
boottime/. The bootgraph* files are compatible with
scripts/bootgraph.pl. The reason for this patch is to provide
data (sysfs/boottime) suitable for automatic test-cases as
well as help for developers to reduce the boot time (debugfs).
Based heavily on the original driver by Jonas Aaberg.
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
Tested-by: Mian Yousaf KAUKAB <mian.yousaf.kaukab@stericsson.com>
---
arch/arm/common/Makefile | 1 +
arch/arm/common/boottime.c | 46 ++++
arch/arm/include/uapi/asm/setup.h | 22 ++
include/linux/boottime.h | 89 +++++++
init/Kconfig | 9 +
init/Makefile | 1 +
init/boottime.c | 475 +++++++++++++++++++++++++++++++++++++
init/main.c | 6 +
8 files changed, 649 insertions(+)
create mode 100644 arch/arm/common/boottime.c
create mode 100644 include/linux/boottime.h
create mode 100644 init/boottime.c
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index e8a4e58..8522356 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
+obj-$(CONFIG_BOOTTIME) += boottime.o
diff --git a/arch/arm/common/boottime.c b/arch/arm/common/boottime.c
new file mode 100644
index 0000000..73e9e04
--- /dev/null
+++ b/arch/arm/common/boottime.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Store boot times measured during for example u-boot startup.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/boottime.h>
+#include <linux/string.h>
+#include <asm/setup.h>
+
+static u32 bootloader_idle;
+static u32 bootloader_total;
+
+static int __init boottime_parse_tag(const struct tag *tag)
+{
+ int i;
+ char buff[BOOTTIME_MAX_NAME_LEN];
+
+ bootloader_idle = tag->u.boottime.idle;
+ bootloader_total = tag->u.boottime.total;
+
+ for (i = 0; i < tag->u.boottime.num; i++) {
+ snprintf(buff, BOOTTIME_MAX_NAME_LEN, "%s+0x0/0x0",
+ tag->u.boottime.entry[i].name);
+ buff[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
+ boottime_mark_wtime(buff, tag->u.boottime.entry[i].time);
+ }
+
+ return 0;
+}
+
+__tagtable(ATAG_BOOTTIME, boottime_parse_tag);
+
+int boottime_bootloader_idle(void)
+{
+ if (bootloader_total == 0)
+ return 0;
+
+ return (int) ((bootloader_idle) / (bootloader_total / 100));
+}
diff --git a/arch/arm/include/uapi/asm/setup.h b/arch/arm/include/uapi/asm/setup.h
index 979ff40..5bc9026 100644
--- a/arch/arm/include/uapi/asm/setup.h
+++ b/arch/arm/include/uapi/asm/setup.h
@@ -143,6 +143,23 @@ struct tag_memclk {
__u32 fmemclk;
};
+/* for automatic boot timing testcases */
+#define ATAG_BOOTTIME 0x41000403
+#define BOOTTIME_MAX_NAME_LEN 64
+#define BOOTTIME_MAX 10
+
+struct boottime_entry {
+ u32 time; /* in us */
+ u8 name[BOOTTIME_MAX_NAME_LEN];
+};
+
+struct tag_boottime {
+ struct boottime_entry entry[BOOTTIME_MAX];
+ u32 idle; /* in us */
+ u32 total; /* in us */
+ u8 num;
+};
+
struct tag {
struct tag_header hdr;
union {
@@ -165,6 +182,11 @@ struct tag {
* DC21285 specific
*/
struct tag_memclk memclk;
+
+ /*
+ * Boot time
+ */
+ struct tag_boottime boottime;
} u;
};
diff --git a/include/linux/boottime.h b/include/linux/boottime.h
new file mode 100644
index 0000000..d330ecd
--- /dev/null
+++ b/include/linux/boottime.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * boottime is a tool for collecting start-up timing
+ * information and can together with boot loader support
+ * display a total system start-up time.
+ *
+ */
+
+#ifndef LINUX_BOOTTIME_H
+#define LINUX_BOOTTIME_H
+
+#ifdef CONFIG_BOOTTIME
+#include <linux/kernel.h>
+
+/**
+ * struct boottime_timer - Callbacks for generic timer.
+ * @init: Function to call at boottime initialization
+ * @get_time: Returns the number of us since start-up
+ * Preferable this is based upon a free running timer.
+ * This is the only required entry.
+ * @finalize: Called before init is executed and boottime is done.
+ */
+struct boottime_timer {
+ int (*init)(void);
+ unsigned long (*get_time)(void);
+ void (*finalize)(void);
+};
+
+/**
+ * boottime_mark_wtime()
+ * Add a sample point with a given time. Useful for adding data collected
+ * by for example a boot loader.
+ * @name: The name of the sample point
+ * @time: The time in us when this point was reached
+ */
+void __init boottime_mark_wtime(char *name, unsigned long time);
+
+/**
+ * boottime_mark()
+ * Add a sample point with the current time.
+ * @name: The name of this sample point
+ */
+void boottime_mark(char *name);
+
+/**
+ * boottime_mark_symbolic()
+ * Add a sample point where the name is a symbolic function
+ * and %pF is needed to get the correct function name.
+ * @name: function name.
+ */
+void __init boottime_mark_symbolic(void *name);
+
+/**
+ * boottime_activate()
+ * Activates boottime and register callbacks.
+ * @bt: struct with callbacks.
+ */
+void __ref boottime_activate(struct boottime_timer *bt);
+
+/**
+ * boottime_deactivate()
+ * This function is called when the kernel boot is done.
+ * (before "free init memory" is called)
+ */
+void boottime_deactivate(void);
+
+/**
+ * boottime_system_up()
+ * A function is called when the basics of the kernel
+ * is up and running.
+ */
+void __init boottime_system_up(void);
+
+#else
+
+#define boottime_mark_wtime(name, time)
+#define boottime_mark(name)
+#define boottime_mark_symbolic(name)
+#define boottime_activate(bt)
+#define boottime_deactivate()
+#define boottime_system_up()
+#endif
+
+#endif /* LINUX_BOOTTIME_H */
diff --git a/init/Kconfig b/init/Kconfig
index 6fdd6e3..85a34aa 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1476,6 +1476,15 @@ config PROFILING
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
+config BOOTTIME
+ bool "Boot time measurements"
+ default n
+ help
+ Adds sysfs entries (boottime/) with start-up timing information.
+ If CONFIG_DEBUG_FS is enabled, detailed information about the
+ boot time, including system load during boot can be extracted.
+ This information can be visualised with help of the bootgraph script.
+
#
# Place an empty function call at each tracepoint site. Can be
# dynamically changed for a probe function.
diff --git a/init/Makefile b/init/Makefile
index 7bc47ee..356d529 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -9,6 +9,7 @@ else
obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o
endif
obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
+obj-$(CONFIG_BOOTTIME) += boottime.o
ifneq ($(CONFIG_ARCH_INIT_TASK),y)
obj-y += init_task.o
diff --git a/init/boottime.c b/init/boottime.c
new file mode 100644
index 0000000..cef31f6
--- /dev/null
+++ b/init/boottime.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009-2010
+ *
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * boottime is a tool for collecting start-up timing
+ * information and can together with boot loader support
+ * display a total system start-up time.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/spinlock.h>
+#include <linux/boottime.h>
+#include <linux/kernel_stat.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+
+/*
+ * BOOTTIME_MAX_NAME_LEN is defined in arch/arm/include/asm/setup.h to 64.
+ * No crisis if they don't match.
+ */
+#ifndef BOOTTIME_MAX_NAME_LEN
+#define BOOTTIME_MAX_NAME_LEN 64
+#endif
+
+/*
+ * We have a few static entries, since it is good to have measure points
+ * before the system is up and running properly
+ */
+#define NUM_STATIC_BOOTTIME_ENTRIES 32
+
+struct boottime_list {
+ struct list_head list;
+ char name[BOOTTIME_MAX_NAME_LEN];
+ /* Time in us since power on, possible including boot loader. */
+ unsigned long time;
+ bool cpu_load;
+ struct kernel_cpustat cpu_usage[NR_CPUS];
+};
+
+enum boottime_filter_type {
+ BOOTTIME_FILTER_OUT_ZERO,
+ BOOTTIME_FILTER_OUT_LESS_100,
+ BOOTTIME_FILTER_NOTHING,
+};
+
+enum boottime_symbolic_print {
+ BOOTTIME_SYMBOLIC_PRINT,
+ BOOTTIME_NORMAL_PRINT,
+};
+
+enum boottime_cpu_load {
+ BOOTTIME_CPU_LOAD,
+ BOOTTIME_NO_CPU_LOAD,
+};
+
+static LIST_HEAD(boottime_list);
+static DEFINE_SPINLOCK(boottime_list_lock);
+static struct boottime_timer boottime_timer;
+static int num_const_boottime_list;
+static struct boottime_list const_boottime_list[NUM_STATIC_BOOTTIME_ENTRIES];
+static unsigned long time_kernel_done;
+static unsigned long time_bootloader_done;
+static bool system_up;
+static bool boottime_done;
+
+int __attribute__((weak)) boottime_arch_startup(void)
+{
+ return 0;
+}
+
+int __attribute__((weak)) boottime_bootloader_idle(void)
+{
+ return 0;
+}
+
+static void boottime_mark_core(char *name,
+ unsigned long time,
+ enum boottime_symbolic_print symbolic,
+ enum boottime_cpu_load cpu_load)
+{
+ struct boottime_list *b;
+ unsigned long flags = 0;
+ int i;
+
+ if (system_up) {
+ b = kmalloc(sizeof(struct boottime_list), GFP_KERNEL);
+ if (!b) {
+ printk(KERN_ERR
+ "boottime: failed to allocate memory!\n");
+ return;
+ }
+
+ } else {
+ if (num_const_boottime_list < NUM_STATIC_BOOTTIME_ENTRIES) {
+ b = &const_boottime_list[num_const_boottime_list];
+ num_const_boottime_list++;
+ } else {
+ printk(KERN_ERR
+ "boottime: too many early measure points!\n");
+ return;
+ }
+ }
+
+ INIT_LIST_HEAD(&b->list);
+
+ if (symbolic == BOOTTIME_SYMBOLIC_PRINT)
+ snprintf(b->name, BOOTTIME_MAX_NAME_LEN, "%pF", name);
+ else
+ strncpy(b->name, name, BOOTTIME_MAX_NAME_LEN);
+
+ b->name[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
+ b->time = time;
+ b->cpu_load = cpu_load;
+
+ if (cpu_load == BOOTTIME_CPU_LOAD && system_up)
+ for_each_possible_cpu(i) {
+ b->cpu_usage[i].cpustat[CPUTIME_SYSTEM] =
+ kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
+ b->cpu_usage[i].cpustat[CPUTIME_IDLE] =
+ kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
+ b->cpu_usage[i].cpustat[CPUTIME_IOWAIT] =
+ kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT];
+ b->cpu_usage[i].cpustat[CPUTIME_IRQ] =
+ kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
+ /*
+ * TODO: Make sure that user, nice, softirq, steal
+ * and guest are not used during boot
+ */
+ }
+ else
+ b->cpu_load = BOOTTIME_NO_CPU_LOAD;
+
+ if (system_up) {
+ spin_lock_irqsave(&boottime_list_lock, flags);
+ list_add(&b->list, &boottime_list);
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+ } else {
+ list_add(&b->list, &boottime_list);
+ }
+}
+
+void __init boottime_mark_wtime(char *name, unsigned long time)
+{
+ boottime_mark_core(name, time,
+ BOOTTIME_NORMAL_PRINT,
+ BOOTTIME_NO_CPU_LOAD);
+}
+
+void __ref boottime_mark_symbolic(void *name)
+{
+
+ if (boottime_done)
+ return;
+
+ if (boottime_timer.get_time)
+ boottime_mark_core((char *) name,
+ boottime_timer.get_time(),
+ BOOTTIME_SYMBOLIC_PRINT,
+ BOOTTIME_CPU_LOAD);
+}
+
+void boottime_mark(char *name)
+{
+ if (boottime_timer.get_time)
+ boottime_mark_core(name,
+ boottime_timer.get_time(),
+ BOOTTIME_NORMAL_PRINT,
+ BOOTTIME_CPU_LOAD);
+}
+
+void __init boottime_activate(struct boottime_timer *bt)
+{
+ struct boottime_list *b;
+ int res = 0;
+ unsigned long flags;
+
+ if (bt == NULL) {
+ printk(KERN_ERR
+ "boottime: error: badly configured\n");
+ return;
+ }
+
+ if (bt->get_time == NULL) {
+ printk(KERN_ERR
+ "boottime: error: you must provide a get_time() function\n");
+ return;
+ }
+ memcpy(&boottime_timer, bt, sizeof(struct boottime_timer));
+
+ if (boottime_timer.init)
+ res = boottime_timer.init();
+
+ if (res) {
+ printk(KERN_ERR "boottime: initialization failed\n");
+ return;
+ }
+
+ if (boottime_arch_startup())
+ printk(KERN_ERR
+ "boottime: arch specfic initialization failed\n");
+
+ spin_lock_irqsave(&boottime_list_lock, flags);
+
+ if (!list_empty(&boottime_list)) {
+
+ b = list_first_entry(&boottime_list, struct boottime_list,
+ list);
+ if (b)
+ time_bootloader_done = b->time;
+ }
+
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+}
+
+void __init boottime_system_up(void)
+{
+ system_up = true;
+}
+
+void boottime_deactivate(void)
+{
+ struct boottime_list *b;
+ unsigned long flags;
+
+ boottime_mark("execute_init+0x0/0x0");
+
+ boottime_done = true;
+
+ spin_lock_irqsave(&boottime_list_lock, flags);
+ b = list_first_entry(&boottime_list, struct boottime_list, list);
+ spin_unlock_irqrestore(&boottime_list_lock, flags);
+
+ time_kernel_done = b->time;
+
+ if (boottime_timer.finalize)
+ boottime_timer.finalize();
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void boottime_debugfs_load(struct seq_file *s,
+ struct boottime_list *b,
+ struct boottime_list *p)
+{
+ int i;
+ unsigned long total_p, total_b;
+ unsigned long system_total, idle_total, irq_total, iowait_total;
+ unsigned long system_load, idle_load, irq_load, iowait_load;
+
+ for_each_possible_cpu(i) {
+ total_b = (b->cpu_usage[i].cpustat[CPUTIME_SYSTEM] +
+ b->cpu_usage[i].cpustat[CPUTIME_IDLE] +
+ b->cpu_usage[i].cpustat[CPUTIME_IOWAIT] +
+ b->cpu_usage[i].cpustat[CPUTIME_IRQ]);
+
+ total_p = (p->cpu_usage[i].cpustat[CPUTIME_SYSTEM] +
+ p->cpu_usage[i].cpustat[CPUTIME_IDLE] +
+ p->cpu_usage[i].cpustat[CPUTIME_IOWAIT] +
+ p->cpu_usage[i].cpustat[CPUTIME_IRQ]);
+
+ if (total_b == total_p)
+ continue;
+
+ system_total = b->cpu_usage[i].cpustat[CPUTIME_SYSTEM]
+ - p->cpu_usage[i].cpustat[CPUTIME_SYSTEM];
+ idle_total = b->cpu_usage[i].cpustat[CPUTIME_IDLE]
+ - p->cpu_usage[i].cpustat[CPUTIME_IDLE];
+ irq_total = b->cpu_usage[i].cpustat[CPUTIME_IRQ]
+ - p->cpu_usage[i].cpustat[CPUTIME_IRQ];
+ iowait_total = b->cpu_usage[i].cpustat[CPUTIME_IOWAIT]
+ - p->cpu_usage[i].cpustat[CPUTIME_IOWAIT];
+
+ system_load = (100 * system_total / (total_b - total_p));
+ idle_load = (100 * idle_total / (total_b - total_p));
+ irq_load = (100 * irq_total / (total_b - total_p));
+ iowait_load = (100 * iowait_total / (total_b - total_p));
+
+ seq_printf(s,
+ " cpu%d system: %lu%% idle: %lu%% iowait: %lu%% irq: %lu%%",
+ i,
+ system_load,
+ idle_load,
+ iowait_load,
+ irq_load);
+ }
+ seq_printf(s, "\n");
+}
+
+static void boottime_debugfs_print(struct seq_file *s,
+ struct boottime_list *b,
+ struct boottime_list *p)
+{
+ seq_printf(s, "[%5lu.%06lu] calling %s\n",
+ p->time / 1000000,
+ (p->time % 1000000),
+ p->name);
+ seq_printf(s, "[%5lu.%06lu] initcall %s returned 0 after %ld msecs.",
+ b->time / 1000000,
+ (b->time % 1000000),
+ p->name, (b->time - p->time) / 1000);
+
+ if (p->cpu_load == BOOTTIME_NO_CPU_LOAD ||
+ b->cpu_load == BOOTTIME_NO_CPU_LOAD) {
+ seq_printf(s, "\n");
+ return;
+ }
+
+ boottime_debugfs_load(s, b, p);
+}
+
+static int boottime_debugfs_bootgraph_show(struct seq_file *s, void *iter)
+{
+ struct boottime_list *b, *p = NULL, *old_p = NULL;
+ enum boottime_filter_type filter = (int)s->private;
+
+ list_for_each_entry_reverse(b, &boottime_list, list) {
+ if (p) {
+ if (!(filter == BOOTTIME_FILTER_OUT_ZERO &&
+ (b->time - p->time) / 1000 == 0)
+ && !(filter == BOOTTIME_FILTER_OUT_LESS_100 &&
+ (b->time - p->time) < 100 * 1000))
+ boottime_debugfs_print(s, b, p);
+ old_p = p;
+ }
+ p = b;
+ }
+
+ if (filter == BOOTTIME_FILTER_NOTHING && p)
+ boottime_debugfs_print(s, p, p);
+
+ if (p)
+ seq_printf(s, "[%5lu.%06lu] Freeing init memory: 0K\n",
+ p->time / 1000000, p->time % 1000000);
+ return 0;
+}
+
+static int boottime_debugfs_summary_show(struct seq_file *s, void *data)
+{
+ struct boottime_list *b, b_zero;
+
+ if (time_bootloader_done)
+ seq_printf(s, "bootloader: %ld msecs\n",
+ time_bootloader_done / 1000);
+
+ seq_printf(s, "kernel: %ld msecs\ntotal: %ld msecs\n",
+ (time_kernel_done - time_bootloader_done) / 1000,
+ time_kernel_done / 1000);
+ seq_printf(s, "kernel:");
+ b = list_first_entry(&boottime_list,
+ struct boottime_list, list);
+ memset(&b_zero, 0, sizeof(struct boottime_list));
+ boottime_debugfs_load(s, b, &b_zero);
+
+ if (time_bootloader_done)
+ seq_printf(s,
+ "bootloader: cpu0 system: %d%% idle: %d%% iowait: 0%% irq: 0%%\n",
+ 100 - boottime_bootloader_idle(),
+ boottime_bootloader_idle());
+ return 0;
+}
+
+static int boottime_debugfs_bootgraph_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file,
+ boottime_debugfs_bootgraph_show,
+ inode->i_private);
+}
+
+static int boottime_debugfs_summary_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file,
+ boottime_debugfs_summary_show,
+ inode->i_private);
+}
+
+static const struct file_operations boottime_debugfs_bootgraph_operations = {
+ .open = boottime_debugfs_bootgraph_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations boottime_debugfs_summary_operations = {
+ .open = boottime_debugfs_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+void boottime_debugfs_init(void)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("boottime", NULL);
+
+ (void) debugfs_create_file("bootgraph", S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_NOTHING,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("bootgraph_all_except0", S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_OUT_ZERO,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("bootgraph_larger100",
+ S_IFREG | S_IRUGO,
+ dir, (void *)BOOTTIME_FILTER_OUT_LESS_100,
+ &boottime_debugfs_bootgraph_operations);
+ (void) debugfs_create_file("summary", S_IFREG | S_IRUGO,
+ dir, NULL,
+ &boottime_debugfs_summary_operations);
+}
+#else
+#define boottime_debugfs_init(x)
+#endif
+
+static ssize_t show_bootloader(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%ld\n", time_bootloader_done / 1000);
+}
+
+static ssize_t show_kernel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%ld\n",
+ (time_kernel_done - time_bootloader_done) / 1000);
+}
+
+DEVICE_ATTR(kernel, 0444, show_kernel, NULL);
+DEVICE_ATTR(bootloader, 0444, show_bootloader, NULL);
+
+static struct attribute *boottime_sysfs_entries[] = {
+ &dev_attr_kernel.attr,
+ &dev_attr_bootloader.attr,
+ NULL
+};
+
+static struct attribute_group boottime_attr_grp = {
+ .name = NULL,
+ .attrs = boottime_sysfs_entries,
+};
+
+static int __init boottime_init(void)
+{
+ struct kobject *boottime_kobj;
+
+ boottime_kobj = kobject_create_and_add("boottime", NULL);
+ if (!boottime_kobj) {
+ printk(KERN_ERR "boottime: out of memory!\n");
+ return -ENOMEM;
+ }
+
+ if (sysfs_create_group(boottime_kobj, &boottime_attr_grp) < 0) {
+ kobject_put(boottime_kobj);
+ printk(KERN_ERR "boottime: Failed creating sysfs group\n");
+ return -ENOMEM;
+ }
+
+ boottime_debugfs_init();
+
+ return 0;
+}
+
+late_initcall(boottime_init);
diff --git a/init/main.c b/init/main.c
index 9cf77ab..d404632 100644
--- a/init/main.c
+++ b/init/main.c
@@ -70,6 +70,7 @@
#include <linux/perf_event.h>
#include <linux/file.h>
#include <linux/ptrace.h>
+#include <linux/boottime.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -680,6 +681,8 @@ int __init_or_module do_one_initcall(initcall_t fn)
int count = preempt_count();
int ret;
+ boottime_mark_symbolic(fn);
+
if (initcall_debug)
ret = do_one_initcall_debug(fn);
else
@@ -805,6 +808,7 @@ static int __ref kernel_init(void *unused)
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
+ boottime_deactivate();
free_initmem();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
@@ -867,6 +871,7 @@ static void __init kernel_init_freeable(void)
do_pre_smp_initcalls();
lockup_detector_init();
+ boottime_system_up();
smp_init();
sched_init_smp();
@@ -889,6 +894,7 @@ static void __init kernel_init_freeable(void)
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
ramdisk_execute_command = NULL;
+ boottime_mark("mount+0x0/0x0");
prepare_namespace();
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/2] clocksource: clksrc-dbx500-prcmu: Add boottime support
From: Lee Jones @ 2012-11-15 10:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352973847-21605-1-git-send-email-lee.jones@linaro.org>
Create a call-back to provide boottime functionality with a means
to gain access to CPU run time information. This call-back will be
invoked numerous times during system boot in order to obtain and
log various time increments throughout the booting process precisely.
Based heavily on the original driver by Jonas Aaberg.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/clocksource/clksrc-dbx500-prcmu.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
index c26c369..0069cd9 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -14,6 +14,7 @@
*/
#include <linux/clockchips.h>
#include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/boottime.h>
#include <asm/sched_clock.h>
@@ -68,6 +69,23 @@ static u32 notrace dbx500_prcmu_sched_clock_read(void)
#endif
+#ifdef CONFIG_BOOTTIME
+static unsigned long __init boottime_get_time(void)
+{
+ return div_s64(clocksource_cyc2ns(clocksource_dbx500_prcmu.read(
+ &clocksource_dbx500_prcmu),
+ clocksource_dbx500_prcmu.mult,
+ clocksource_dbx500_prcmu.shift),
+ 1000);
+}
+
+static struct boottime_timer __initdata boottime_timer = {
+ .init = NULL,
+ .get_time = boottime_get_time,
+ .finalize = NULL,
+};
+#endif
+
void __init clksrc_dbx500_prcmu_init(void __iomem *base)
{
clksrc_dbx500_timer_base = base;
@@ -90,4 +108,6 @@ void __init clksrc_dbx500_prcmu_init(void __iomem *base)
32, RATE_32K);
#endif
clocksource_register_hz(&clocksource_dbx500_prcmu, RATE_32K);
+
+ boottime_activate(&boottime_timer);
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 6/6] usb: chipidea: usbmisc: add post handling and errata fix for mx25
From: Martin Fuzzey @ 2012-11-15 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352894137-2050-7-git-send-email-m.grzeschik@pengutronix.de>
Hi,
On Wed, Nov 14, 2012 at 12:55 PM, Michael Grzeschik
<m.grzeschik@pengutronix.de> wrote:
> @@ -213,6 +216,15 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
> goto put_np;
> }
>
> + if (usbmisc_ops && usbmisc_ops->post) {
> + ret = usbmisc_ops->post(&pdev->dev);
> + if (ret) {
> + dev_err(&pdev->dev,
> + "usbmisc post failed, ret=%d\n", ret);
> + goto err;
> + }
> + }
> +
> data->ci_pdev = plat_ci;
> platform_set_drvdata(pdev, data);
>
This hunk fails to apply for me on 3.7-rc5:
error: while searching for:
goto put_np;
}
data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);
Regards,
Martin
^ permalink raw reply
* [PATCH 0/2] Boottime: measure bootloader and kernel bootup time
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-15 10:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352973847-21605-1-git-send-email-lee.jones@linaro.org>
On 10:04 Thu 15 Nov , Lee Jones wrote:
> This patchset supplies a new tool which measures boottime inclusive
> of bootloader involvement. It seems to be accurate and adds no
> latency to the booting of the system.
>
> In the first round of testing we booted the kernel 3 times each with
> boottime enabled and disabled. Actually, when it was disabled, the
> code was completely removed from the kernel source and the kernel was
> rebuilt. The difference between present & enabled and completely
> removed was very little indeed. In fact, averaging out the 3 runs of
> each, when boottime was enabled the system booted 4ms _faster_, go
> figure!
>
> Enabled Disabled
> 1st run 2.983093 2.985168
> 2nd run 2.973266 2.971801
> 3rd run 2.975402 2.987304
> Average 2.977254 2.981424 -0.004171 (-4ms)
>
>
> For the next round of testing, we delayed the bootloader for varying
> amounts of time, then started to remove key components from kernel
> functionality to see if the boottime system would pick-up on them.
>
> /* Hang around in the bootloader for a while. */
> $ cat /sys/kernel/debug/boottime/summary
> kernel: 42864 msecs
> total: 42864 msecs
> kernel: cpu0 system: 56% idle: 43% iowait: 0% irq: 0%
> cpu1 system: 4% idle: 95% iowait: 0% irq: 0%
>
> /* Hang around in the bootloader for a smaller amount of time. */
> kernel: 12351 msecs
> total: 12351 msecs
> kernel: cpu0 system: 56% idle: 43% iowait: 0% irq: 0%
> cpu1 system: 2% idle: 97% iowait: 0% irq: 0%
>
> /* Instant boot. (1st run) */
> kernel: 7833 msecs
> total: 7833 msecs
> kernel: cpu0 system: 55% idle: 44% iowait: 0% irq: 0%
> cpu1 system: 3% idle: 96% iowait: 0% irq: 0%
>
> /* Instant boot. (2nd run) */
> kernel: 7817 msecs
> total: 7817 msecs
> kernel: cpu0 system: 53% idle: 46% iowait: 0% irq: 0%
> cpu1 system: 8% idle: 91% iowait: 0% irq: 0%
>
> /* Instant boot. (3rd run) */
> kernel: 7747 msecs
> total: 7747 msecs
> kernel: cpu0 system: 56% idle: 42% iowait: 0% irq: 0%
> cpu1 system: 2% idle: 97% iowait: 0% irq: 0%
7/8s? on a u9500 wow it's really slow
I do 2/3s here
Best Regards.
J.
^ permalink raw reply
* [PATCH 1/2] Boottime: A tool for automatic measurement of kernel/bootloader boot time
From: Kyungmin Park @ 2012-11-15 10:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1352973847-21605-2-git-send-email-lee.jones@linaro.org>
Hi,
On 11/15/12, Lee Jones <lee.jones@linaro.org> wrote:
> The overhead is very low and the results will be found under
> sysfs/bootime, as well as detailed results in debugfs under
> boottime/. The bootgraph* files are compatible with
> scripts/bootgraph.pl. The reason for this patch is to provide
> data (sysfs/boottime) suitable for automatic test-cases as
> well as help for developers to reduce the boot time (debugfs).
>
> Based heavily on the original driver by Jonas Aaberg.
>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
> Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
> Tested-by: Mian Yousaf KAUKAB <mian.yousaf.kaukab@stericsson.com>
> ---
> arch/arm/common/Makefile | 1 +
> arch/arm/common/boottime.c | 46 ++++
> arch/arm/include/uapi/asm/setup.h | 22 ++
> include/linux/boottime.h | 89 +++++++
> init/Kconfig | 9 +
> init/Makefile | 1 +
> init/boottime.c | 475
> +++++++++++++++++++++++++++++++++++++
> init/main.c | 6 +
> 8 files changed, 649 insertions(+)
> create mode 100644 arch/arm/common/boottime.c
> create mode 100644 include/linux/boottime.h
> create mode 100644 init/boottime.c
>
> diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
> index e8a4e58..8522356 100644
> --- a/arch/arm/common/Makefile
> +++ b/arch/arm/common/Makefile
> @@ -13,3 +13,4 @@ obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
> obj-$(CONFIG_SHARP_SCOOP) += scoop.o
> obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
> obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
> +obj-$(CONFIG_BOOTTIME) += boottime.o
> diff --git a/arch/arm/common/boottime.c b/arch/arm/common/boottime.c
> new file mode 100644
> index 0000000..73e9e04
> --- /dev/null
> +++ b/arch/arm/common/boottime.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright (C) ST-Ericsson SA 2009-2010
> + *
> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + *
> + * Store boot times measured during for example u-boot startup.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/boottime.h>
> +#include <linux/string.h>
> +#include <asm/setup.h>
> +
> +static u32 bootloader_idle;
> +static u32 bootloader_total;
> +
> +static int __init boottime_parse_tag(const struct tag *tag)
> +{
> + int i;
> + char buff[BOOTTIME_MAX_NAME_LEN];
> +
> + bootloader_idle = tag->u.boottime.idle;
> + bootloader_total = tag->u.boottime.total;
> +
> + for (i = 0; i < tag->u.boottime.num; i++) {
> + snprintf(buff, BOOTTIME_MAX_NAME_LEN, "%s+0x0/0x0",
> + tag->u.boottime.entry[i].name);
> + buff[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
> + boottime_mark_wtime(buff, tag->u.boottime.entry[i].time);
> + }
> +
> + return 0;
> +}
> +
> +__tagtable(ATAG_BOOTTIME, boottime_parse_tag);
> +
> +int boottime_bootloader_idle(void)
> +{
> + if (bootloader_total == 0)
> + return 0;
> +
> + return (int) ((bootloader_idle) / (bootloader_total / 100));
> +}
> diff --git a/arch/arm/include/uapi/asm/setup.h
> b/arch/arm/include/uapi/asm/setup.h
> index 979ff40..5bc9026 100644
> --- a/arch/arm/include/uapi/asm/setup.h
> +++ b/arch/arm/include/uapi/asm/setup.h
> @@ -143,6 +143,23 @@ struct tag_memclk {
> __u32 fmemclk;
> };
>
> +/* for automatic boot timing testcases */
> +#define ATAG_BOOTTIME 0x41000403
Where can I refer this ATAG usage? can you point out the reference URL
or patches?
Thank you,
Kyungmin Park
> +#define BOOTTIME_MAX_NAME_LEN 64
> +#define BOOTTIME_MAX 10
> +
> +struct boottime_entry {
> + u32 time; /* in us */
> + u8 name[BOOTTIME_MAX_NAME_LEN];
> +};
> +
> +struct tag_boottime {
> + struct boottime_entry entry[BOOTTIME_MAX];
> + u32 idle; /* in us */
> + u32 total; /* in us */
> + u8 num;
> +};
> +
> struct tag {
> struct tag_header hdr;
> union {
> @@ -165,6 +182,11 @@ struct tag {
> * DC21285 specific
> */
> struct tag_memclk memclk;
> +
> + /*
> + * Boot time
> + */
> + struct tag_boottime boottime;
> } u;
> };
>
> diff --git a/include/linux/boottime.h b/include/linux/boottime.h
> new file mode 100644
> index 0000000..d330ecd
> --- /dev/null
> +++ b/include/linux/boottime.h
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (C) ST-Ericsson SA 2009-2010
> + *
> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + *
> + * boottime is a tool for collecting start-up timing
> + * information and can together with boot loader support
> + * display a total system start-up time.
> + *
> + */
> +
> +#ifndef LINUX_BOOTTIME_H
> +#define LINUX_BOOTTIME_H
> +
> +#ifdef CONFIG_BOOTTIME
> +#include <linux/kernel.h>
> +
> +/**
> + * struct boottime_timer - Callbacks for generic timer.
> + * @init: Function to call at boottime initialization
> + * @get_time: Returns the number of us since start-up
> + * Preferable this is based upon a free running timer.
> + * This is the only required entry.
> + * @finalize: Called before init is executed and boottime is done.
> + */
> +struct boottime_timer {
> + int (*init)(void);
> + unsigned long (*get_time)(void);
> + void (*finalize)(void);
> +};
> +
> +/**
> + * boottime_mark_wtime()
> + * Add a sample point with a given time. Useful for adding data collected
> + * by for example a boot loader.
> + * @name: The name of the sample point
> + * @time: The time in us when this point was reached
> + */
> +void __init boottime_mark_wtime(char *name, unsigned long time);
> +
> +/**
> + * boottime_mark()
> + * Add a sample point with the current time.
> + * @name: The name of this sample point
> + */
> +void boottime_mark(char *name);
> +
> +/**
> + * boottime_mark_symbolic()
> + * Add a sample point where the name is a symbolic function
> + * and %pF is needed to get the correct function name.
> + * @name: function name.
> + */
> +void __init boottime_mark_symbolic(void *name);
> +
> +/**
> + * boottime_activate()
> + * Activates boottime and register callbacks.
> + * @bt: struct with callbacks.
> + */
> +void __ref boottime_activate(struct boottime_timer *bt);
> +
> +/**
> + * boottime_deactivate()
> + * This function is called when the kernel boot is done.
> + * (before "free init memory" is called)
> + */
> +void boottime_deactivate(void);
> +
> +/**
> + * boottime_system_up()
> + * A function is called when the basics of the kernel
> + * is up and running.
> + */
> +void __init boottime_system_up(void);
> +
> +#else
> +
> +#define boottime_mark_wtime(name, time)
> +#define boottime_mark(name)
> +#define boottime_mark_symbolic(name)
> +#define boottime_activate(bt)
> +#define boottime_deactivate()
> +#define boottime_system_up()
> +#endif
> +
> +#endif /* LINUX_BOOTTIME_H */
> diff --git a/init/Kconfig b/init/Kconfig
> index 6fdd6e3..85a34aa 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1476,6 +1476,15 @@ config PROFILING
> Say Y here to enable the extended profiling support mechanisms used
> by profilers such as OProfile.
>
> +config BOOTTIME
> + bool "Boot time measurements"
> + default n
> + help
> + Adds sysfs entries (boottime/) with start-up timing information.
> + If CONFIG_DEBUG_FS is enabled, detailed information about the
> + boot time, including system load during boot can be extracted.
> + This information can be visualised with help of the bootgraph script.
> +
> #
> # Place an empty function call at each tracepoint site. Can be
> # dynamically changed for a probe function.
> diff --git a/init/Makefile b/init/Makefile
> index 7bc47ee..356d529 100644
> --- a/init/Makefile
> +++ b/init/Makefile
> @@ -9,6 +9,7 @@ else
> obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o
> endif
> obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o
> +obj-$(CONFIG_BOOTTIME) += boottime.o
>
> ifneq ($(CONFIG_ARCH_INIT_TASK),y)
> obj-y += init_task.o
> diff --git a/init/boottime.c b/init/boottime.c
> new file mode 100644
> index 0000000..cef31f6
> --- /dev/null
> +++ b/init/boottime.c
> @@ -0,0 +1,475 @@
> +/*
> + * Copyright (C) ST-Ericsson SA 2009-2010
> + *
> + * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + *
> + * boottime is a tool for collecting start-up timing
> + * information and can together with boot loader support
> + * display a total system start-up time.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/list.h>
> +#include <linux/seq_file.h>
> +#include <linux/debugfs.h>
> +#include <linux/spinlock.h>
> +#include <linux/boottime.h>
> +#include <linux/kernel_stat.h>
> +#include <linux/kobject.h>
> +#include <linux/device.h>
> +#include <linux/sysfs.h>
> +#include <linux/slab.h>
> +
> +/*
> + * BOOTTIME_MAX_NAME_LEN is defined in arch/arm/include/asm/setup.h to 64.
> + * No crisis if they don't match.
> + */
> +#ifndef BOOTTIME_MAX_NAME_LEN
> +#define BOOTTIME_MAX_NAME_LEN 64
> +#endif
> +
> +/*
> + * We have a few static entries, since it is good to have measure points
> + * before the system is up and running properly
> + */
> +#define NUM_STATIC_BOOTTIME_ENTRIES 32
> +
> +struct boottime_list {
> + struct list_head list;
> + char name[BOOTTIME_MAX_NAME_LEN];
> + /* Time in us since power on, possible including boot loader. */
> + unsigned long time;
> + bool cpu_load;
> + struct kernel_cpustat cpu_usage[NR_CPUS];
> +};
> +
> +enum boottime_filter_type {
> + BOOTTIME_FILTER_OUT_ZERO,
> + BOOTTIME_FILTER_OUT_LESS_100,
> + BOOTTIME_FILTER_NOTHING,
> +};
> +
> +enum boottime_symbolic_print {
> + BOOTTIME_SYMBOLIC_PRINT,
> + BOOTTIME_NORMAL_PRINT,
> +};
> +
> +enum boottime_cpu_load {
> + BOOTTIME_CPU_LOAD,
> + BOOTTIME_NO_CPU_LOAD,
> +};
> +
> +static LIST_HEAD(boottime_list);
> +static DEFINE_SPINLOCK(boottime_list_lock);
> +static struct boottime_timer boottime_timer;
> +static int num_const_boottime_list;
> +static struct boottime_list
> const_boottime_list[NUM_STATIC_BOOTTIME_ENTRIES];
> +static unsigned long time_kernel_done;
> +static unsigned long time_bootloader_done;
> +static bool system_up;
> +static bool boottime_done;
> +
> +int __attribute__((weak)) boottime_arch_startup(void)
> +{
> + return 0;
> +}
> +
> +int __attribute__((weak)) boottime_bootloader_idle(void)
> +{
> + return 0;
> +}
> +
> +static void boottime_mark_core(char *name,
> + unsigned long time,
> + enum boottime_symbolic_print symbolic,
> + enum boottime_cpu_load cpu_load)
> +{
> + struct boottime_list *b;
> + unsigned long flags = 0;
> + int i;
> +
> + if (system_up) {
> + b = kmalloc(sizeof(struct boottime_list), GFP_KERNEL);
> + if (!b) {
> + printk(KERN_ERR
> + "boottime: failed to allocate memory!\n");
> + return;
> + }
> +
> + } else {
> + if (num_const_boottime_list < NUM_STATIC_BOOTTIME_ENTRIES) {
> + b = &const_boottime_list[num_const_boottime_list];
> + num_const_boottime_list++;
> + } else {
> + printk(KERN_ERR
> + "boottime: too many early measure points!\n");
> + return;
> + }
> + }
> +
> + INIT_LIST_HEAD(&b->list);
> +
> + if (symbolic == BOOTTIME_SYMBOLIC_PRINT)
> + snprintf(b->name, BOOTTIME_MAX_NAME_LEN, "%pF", name);
> + else
> + strncpy(b->name, name, BOOTTIME_MAX_NAME_LEN);
> +
> + b->name[BOOTTIME_MAX_NAME_LEN - 1] = '\0';
> + b->time = time;
> + b->cpu_load = cpu_load;
> +
> + if (cpu_load == BOOTTIME_CPU_LOAD && system_up)
> + for_each_possible_cpu(i) {
> + b->cpu_usage[i].cpustat[CPUTIME_SYSTEM] =
> + kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM];
> + b->cpu_usage[i].cpustat[CPUTIME_IDLE] =
> + kcpustat_cpu(i).cpustat[CPUTIME_IDLE];
> + b->cpu_usage[i].cpustat[CPUTIME_IOWAIT] =
> + kcpustat_cpu(i).cpustat[CPUTIME_IOWAIT];
> + b->cpu_usage[i].cpustat[CPUTIME_IRQ] =
> + kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
> + /*
> + * TODO: Make sure that user, nice, softirq, steal
> + * and guest are not used during boot
> + */
> + }
> + else
> + b->cpu_load = BOOTTIME_NO_CPU_LOAD;
> +
> + if (system_up) {
> + spin_lock_irqsave(&boottime_list_lock, flags);
> + list_add(&b->list, &boottime_list);
> + spin_unlock_irqrestore(&boottime_list_lock, flags);
> + } else {
> + list_add(&b->list, &boottime_list);
> + }
> +}
> +
> +void __init boottime_mark_wtime(char *name, unsigned long time)
> +{
> + boottime_mark_core(name, time,
> + BOOTTIME_NORMAL_PRINT,
> + BOOTTIME_NO_CPU_LOAD);
> +}
> +
> +void __ref boottime_mark_symbolic(void *name)
> +{
> +
> + if (boottime_done)
> + return;
> +
> + if (boottime_timer.get_time)
> + boottime_mark_core((char *) name,
> + boottime_timer.get_time(),
> + BOOTTIME_SYMBOLIC_PRINT,
> + BOOTTIME_CPU_LOAD);
> +}
> +
> +void boottime_mark(char *name)
> +{
> + if (boottime_timer.get_time)
> + boottime_mark_core(name,
> + boottime_timer.get_time(),
> + BOOTTIME_NORMAL_PRINT,
> + BOOTTIME_CPU_LOAD);
> +}
> +
> +void __init boottime_activate(struct boottime_timer *bt)
> +{
> + struct boottime_list *b;
> + int res = 0;
> + unsigned long flags;
> +
> + if (bt == NULL) {
> + printk(KERN_ERR
> + "boottime: error: badly configured\n");
> + return;
> + }
> +
> + if (bt->get_time == NULL) {
> + printk(KERN_ERR
> + "boottime: error: you must provide a get_time() function\n");
> + return;
> + }
> + memcpy(&boottime_timer, bt, sizeof(struct boottime_timer));
> +
> + if (boottime_timer.init)
> + res = boottime_timer.init();
> +
> + if (res) {
> + printk(KERN_ERR "boottime: initialization failed\n");
> + return;
> + }
> +
> + if (boottime_arch_startup())
> + printk(KERN_ERR
> + "boottime: arch specfic initialization failed\n");
> +
> + spin_lock_irqsave(&boottime_list_lock, flags);
> +
> + if (!list_empty(&boottime_list)) {
> +
> + b = list_first_entry(&boottime_list, struct boottime_list,
> + list);
> + if (b)
> + time_bootloader_done = b->time;
> + }
> +
> + spin_unlock_irqrestore(&boottime_list_lock, flags);
> +}
> +
> +void __init boottime_system_up(void)
> +{
> + system_up = true;
> +}
> +
> +void boottime_deactivate(void)
> +{
> + struct boottime_list *b;
> + unsigned long flags;
> +
> + boottime_mark("execute_init+0x0/0x0");
> +
> + boottime_done = true;
> +
> + spin_lock_irqsave(&boottime_list_lock, flags);
> + b = list_first_entry(&boottime_list, struct boottime_list, list);
> + spin_unlock_irqrestore(&boottime_list_lock, flags);
> +
> + time_kernel_done = b->time;
> +
> + if (boottime_timer.finalize)
> + boottime_timer.finalize();
> +}
> +
> +#ifdef CONFIG_DEBUG_FS
> +static void boottime_debugfs_load(struct seq_file *s,
> + struct boottime_list *b,
> + struct boottime_list *p)
> +{
> + int i;
> + unsigned long total_p, total_b;
> + unsigned long system_total, idle_total, irq_total, iowait_total;
> + unsigned long system_load, idle_load, irq_load, iowait_load;
> +
> + for_each_possible_cpu(i) {
> + total_b = (b->cpu_usage[i].cpustat[CPUTIME_SYSTEM] +
> + b->cpu_usage[i].cpustat[CPUTIME_IDLE] +
> + b->cpu_usage[i].cpustat[CPUTIME_IOWAIT] +
> + b->cpu_usage[i].cpustat[CPUTIME_IRQ]);
> +
> + total_p = (p->cpu_usage[i].cpustat[CPUTIME_SYSTEM] +
> + p->cpu_usage[i].cpustat[CPUTIME_IDLE] +
> + p->cpu_usage[i].cpustat[CPUTIME_IOWAIT] +
> + p->cpu_usage[i].cpustat[CPUTIME_IRQ]);
> +
> + if (total_b == total_p)
> + continue;
> +
> + system_total = b->cpu_usage[i].cpustat[CPUTIME_SYSTEM]
> + - p->cpu_usage[i].cpustat[CPUTIME_SYSTEM];
> + idle_total = b->cpu_usage[i].cpustat[CPUTIME_IDLE]
> + - p->cpu_usage[i].cpustat[CPUTIME_IDLE];
> + irq_total = b->cpu_usage[i].cpustat[CPUTIME_IRQ]
> + - p->cpu_usage[i].cpustat[CPUTIME_IRQ];
> + iowait_total = b->cpu_usage[i].cpustat[CPUTIME_IOWAIT]
> + - p->cpu_usage[i].cpustat[CPUTIME_IOWAIT];
> +
> + system_load = (100 * system_total / (total_b - total_p));
> + idle_load = (100 * idle_total / (total_b - total_p));
> + irq_load = (100 * irq_total / (total_b - total_p));
> + iowait_load = (100 * iowait_total / (total_b - total_p));
> +
> + seq_printf(s,
> + " cpu%d system: %lu%% idle: %lu%% iowait: %lu%% irq: %lu%%",
> + i,
> + system_load,
> + idle_load,
> + iowait_load,
> + irq_load);
> + }
> + seq_printf(s, "\n");
> +}
> +
> +static void boottime_debugfs_print(struct seq_file *s,
> + struct boottime_list *b,
> + struct boottime_list *p)
> +{
> + seq_printf(s, "[%5lu.%06lu] calling %s\n",
> + p->time / 1000000,
> + (p->time % 1000000),
> + p->name);
> + seq_printf(s, "[%5lu.%06lu] initcall %s returned 0 after %ld msecs.",
> + b->time / 1000000,
> + (b->time % 1000000),
> + p->name, (b->time - p->time) / 1000);
> +
> + if (p->cpu_load == BOOTTIME_NO_CPU_LOAD ||
> + b->cpu_load == BOOTTIME_NO_CPU_LOAD) {
> + seq_printf(s, "\n");
> + return;
> + }
> +
> + boottime_debugfs_load(s, b, p);
> +}
> +
> +static int boottime_debugfs_bootgraph_show(struct seq_file *s, void *iter)
> +{
> + struct boottime_list *b, *p = NULL, *old_p = NULL;
> + enum boottime_filter_type filter = (int)s->private;
> +
> + list_for_each_entry_reverse(b, &boottime_list, list) {
> + if (p) {
> + if (!(filter == BOOTTIME_FILTER_OUT_ZERO &&
> + (b->time - p->time) / 1000 == 0)
> + && !(filter == BOOTTIME_FILTER_OUT_LESS_100 &&
> + (b->time - p->time) < 100 * 1000))
> + boottime_debugfs_print(s, b, p);
> + old_p = p;
> + }
> + p = b;
> + }
> +
> + if (filter == BOOTTIME_FILTER_NOTHING && p)
> + boottime_debugfs_print(s, p, p);
> +
> + if (p)
> + seq_printf(s, "[%5lu.%06lu] Freeing init memory: 0K\n",
> + p->time / 1000000, p->time % 1000000);
> + return 0;
> +}
> +
> +static int boottime_debugfs_summary_show(struct seq_file *s, void *data)
> +{
> + struct boottime_list *b, b_zero;
> +
> + if (time_bootloader_done)
> + seq_printf(s, "bootloader: %ld msecs\n",
> + time_bootloader_done / 1000);
> +
> + seq_printf(s, "kernel: %ld msecs\ntotal: %ld msecs\n",
> + (time_kernel_done - time_bootloader_done) / 1000,
> + time_kernel_done / 1000);
> + seq_printf(s, "kernel:");
> + b = list_first_entry(&boottime_list,
> + struct boottime_list, list);
> + memset(&b_zero, 0, sizeof(struct boottime_list));
> + boottime_debugfs_load(s, b, &b_zero);
> +
> + if (time_bootloader_done)
> + seq_printf(s,
> + "bootloader: cpu0 system: %d%% idle: %d%% iowait: 0%% irq: 0%%\n",
> + 100 - boottime_bootloader_idle(),
> + boottime_bootloader_idle());
> + return 0;
> +}
> +
> +static int boottime_debugfs_bootgraph_open(struct inode *inode,
> + struct file *file)
> +{
> + return single_open(file,
> + boottime_debugfs_bootgraph_show,
> + inode->i_private);
> +}
> +
> +static int boottime_debugfs_summary_open(struct inode *inode,
> + struct file *file)
> +{
> + return single_open(file,
> + boottime_debugfs_summary_show,
> + inode->i_private);
> +}
> +
> +static const struct file_operations boottime_debugfs_bootgraph_operations =
> {
> + .open = boottime_debugfs_bootgraph_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
> +static const struct file_operations boottime_debugfs_summary_operations =
> {
> + .open = boottime_debugfs_summary_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = single_release,
> +};
> +
> +void boottime_debugfs_init(void)
> +{
> + struct dentry *dir;
> +
> + dir = debugfs_create_dir("boottime", NULL);
> +
> + (void) debugfs_create_file("bootgraph", S_IFREG | S_IRUGO,
> + dir, (void *)BOOTTIME_FILTER_NOTHING,
> + &boottime_debugfs_bootgraph_operations);
> + (void) debugfs_create_file("bootgraph_all_except0", S_IFREG | S_IRUGO,
> + dir, (void *)BOOTTIME_FILTER_OUT_ZERO,
> + &boottime_debugfs_bootgraph_operations);
> + (void) debugfs_create_file("bootgraph_larger100",
> + S_IFREG | S_IRUGO,
> + dir, (void *)BOOTTIME_FILTER_OUT_LESS_100,
> + &boottime_debugfs_bootgraph_operations);
> + (void) debugfs_create_file("summary", S_IFREG | S_IRUGO,
> + dir, NULL,
> + &boottime_debugfs_summary_operations);
> +}
> +#else
> +#define boottime_debugfs_init(x)
> +#endif
> +
> +static ssize_t show_bootloader(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return sprintf(buf, "%ld\n", time_bootloader_done / 1000);
> +}
> +
> +static ssize_t show_kernel(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return sprintf(buf, "%ld\n",
> + (time_kernel_done - time_bootloader_done) / 1000);
> +}
> +
> +DEVICE_ATTR(kernel, 0444, show_kernel, NULL);
> +DEVICE_ATTR(bootloader, 0444, show_bootloader, NULL);
> +
> +static struct attribute *boottime_sysfs_entries[] = {
> + &dev_attr_kernel.attr,
> + &dev_attr_bootloader.attr,
> + NULL
> +};
> +
> +static struct attribute_group boottime_attr_grp = {
> + .name = NULL,
> + .attrs = boottime_sysfs_entries,
> +};
> +
> +static int __init boottime_init(void)
> +{
> + struct kobject *boottime_kobj;
> +
> + boottime_kobj = kobject_create_and_add("boottime", NULL);
> + if (!boottime_kobj) {
> + printk(KERN_ERR "boottime: out of memory!\n");
> + return -ENOMEM;
> + }
> +
> + if (sysfs_create_group(boottime_kobj, &boottime_attr_grp) < 0) {
> + kobject_put(boottime_kobj);
> + printk(KERN_ERR "boottime: Failed creating sysfs group\n");
> + return -ENOMEM;
> + }
> +
> + boottime_debugfs_init();
> +
> + return 0;
> +}
> +
> +late_initcall(boottime_init);
> diff --git a/init/main.c b/init/main.c
> index 9cf77ab..d404632 100644
> --- a/init/main.c
> +++ b/init/main.c
> @@ -70,6 +70,7 @@
> #include <linux/perf_event.h>
> #include <linux/file.h>
> #include <linux/ptrace.h>
> +#include <linux/boottime.h>
>
> #include <asm/io.h>
> #include <asm/bugs.h>
> @@ -680,6 +681,8 @@ int __init_or_module do_one_initcall(initcall_t fn)
> int count = preempt_count();
> int ret;
>
> + boottime_mark_symbolic(fn);
> +
> if (initcall_debug)
> ret = do_one_initcall_debug(fn);
> else
> @@ -805,6 +808,7 @@ static int __ref kernel_init(void *unused)
> kernel_init_freeable();
> /* need to finish all async __init code before freeing the memory */
> async_synchronize_full();
> + boottime_deactivate();
> free_initmem();
> mark_rodata_ro();
> system_state = SYSTEM_RUNNING;
> @@ -867,6 +871,7 @@ static void __init kernel_init_freeable(void)
>
> do_pre_smp_initcalls();
> lockup_detector_init();
> + boottime_system_up();
>
> smp_init();
> sched_init_smp();
> @@ -889,6 +894,7 @@ static void __init kernel_init_freeable(void)
>
> if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
> ramdisk_execute_command = NULL;
> + boottime_mark("mount+0x0/0x0");
> prepare_namespace();
> }
>
> --
> 1.7.9.5
>
>
> _______________________________________________
> 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 V2 1/5] arm: mvebu: Added support for coherency fabric in mach-mvebu
From: Will Deacon @ 2012-11-15 10:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50A3F860.5010601@free-electrons.com>
On Wed, Nov 14, 2012 at 08:00:32PM +0000, Gregory CLEMENT wrote:
> On 11/13/2012 11:43 AM, Will Deacon wrote:
> > On Mon, Nov 12, 2012 at 08:21:07PM +0000, Gregory CLEMENT wrote:
> >> On 11/05/2012 03:02 PM, Will Deacon wrote:
> >>> These writels may expand to code containing calls to outer_sync(), which
> >>> will attempt to take a spinlock for the aurora l2. Given that the CPU isn't
> >>> coherent, how does this play out with the exclusive store instruction in the
> >>> lock?
> >>
> >> I dug a little this subject: and I am not sure there is problem. In SMP mode,
> >> only the system cache mode of Aurora is used. In this mode, outer_cache.sync
> >> is void then outer_sync() won't call any function, so there will be no
> >> access to any spinlock.
> >
> > Hmm, that is pretty subtle and it doesn't really solve the bigger picture.
> > printk takes logbuf_lock, for example, and I'm sure that by the time you get
> > to this code you will have relied on exclusives behaving correctly.
> >
>
> Hi Will,
> I get an answer from Marvell engineers:
> "STREX on non-shareable and/or non-cacheable memory regions is supported."
Interesting, thanks for asking them about this. Does this mean that:
1. When not running coherently (i.e. before initialising the
coherency fabric), memory is treated as non-shareable,
non-cacheable?
2. If (1), then are exclusive accesses the only way to achieve
coherent memory accesses in this scenario?
If so, you still have a problem with write locks, where the unlock code does
a regular str to clear the status. atomic_{read,set} also uses regular
memory accesses, so I think you'll get some surprises there when you add
explicit memory barriers and expect things to be visible between threads.
Do memory barriers have different semantics depending on the state of your
coherency fabric?
Cheers,
Will
^ permalink raw reply
* Fwd: [PATCH 1/7] I2c-nomadik: Fix the usage of wait_for_completion_timeout
From: Wolfram Sang @ 2012-11-15 10:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121115095741.GA6280@bnru10>
On Thu, Nov 15, 2012 at 03:27:42PM +0530, Srinidhi Kasagar wrote:
> On Thu, Nov 15, 2012 at 10:29:53 +0100, Wolfram Sang wrote:
> >
> > > > - if (timeout < 0) {
> > > > - dev_err(&dev->adev->dev,
> > > > - "wait_for_completion_timeout "
> > > > - "returned %d waiting for event\n", timeout);
> > > > - status = timeout;
> > > > - }
> > > > -
> > > No, it is wrong. You need to update the status variable in the case of timeout.
> >
> > Looking at the patch context, such code comes later.
> But it causes regressions; without looking at the "later" code, we can't afford merging
> this code now.
Later as in "a few lines later" not "some time later". Or am I missing
something else?
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121115/24943c8e/attachment.sig>
^ permalink raw reply
* [PATCH 6/6] usb: chipidea: usbmisc: add post handling and errata fix for mx25
From: Michael Grzeschik @ 2012-11-15 10:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CALBypN6U=np93ZwnEZqbh=j0Vb_-x630GaktEiv+4K26eYp4Pg@mail.gmail.com>
On Thu, Nov 15, 2012 at 11:08:15AM +0100, Martin Fuzzey wrote:
> On Wed, Nov 14, 2012 at 12:55 PM, Michael Grzeschik
> <m.grzeschik@pengutronix.de> wrote:
> > @@ -213,6 +216,15 @@ static int __devinit ci13xxx_imx_probe(struct platform_device *pdev)
> > goto put_np;
> > }
> >
> > + if (usbmisc_ops && usbmisc_ops->post) {
> > + ret = usbmisc_ops->post(&pdev->dev);
> > + if (ret) {
> > + dev_err(&pdev->dev,
> > + "usbmisc post failed, ret=%d\n", ret);
> > + goto err;
> > + }
> > + }
> > +
> > data->ci_pdev = plat_ci;
> > platform_set_drvdata(pdev, data);
> >
> This hunk fails to apply for me on 3.7-rc5:
> error: while searching for:
> goto put_np;
> }
This is because that series is based on Peter Chen's work. I should have
mentioned this in the cover-letter mail. You can merge his master branch
before adding my series:
https://github.com/hzpeterchen/linux-usb.git
Apart from the latter patches, his work already got queued up by Greg:
http://comments.gmane.org/gmane.linux.usb.general/74537
Thanks,
Michael
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH v3 01/11] clk: samsung: add common clock framework helper functions for Samsung platforms
From: Tomasz Figa @ 2012-11-15 10:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAJuYYwR=9Gx5kx-JwVNUaa8Tej-3NG03U4zbYBKr36rPAOtPvw@mail.gmail.com>
On Thursday 15 of November 2012 14:03:12 Thomas Abraham wrote:
> Hi Tomasz,
>
> Thanks for reviewing these patches!
>
> On 15 November 2012 04:42, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> > Hi Thomas,
> >
> > Looks mostly good, but I have some minor comments inline.
> >
> > On Thursday 15 of November 2012 03:37:23 Thomas Abraham wrote:
> >> All Samsung platforms include different types of clock including
> >> fixed-rate, mux, divider and gate clock types. There are typically
> >> hundreds of such clocks on each of the Samsung platforms. To enable
> >> Samsung platforms to register these clocks using the common clock
> >> framework, a bunch of utility functions are introduced here which
> >> simplify the clock registration process. The clocks are usually
> >> statically instantiated and registered with common clock framework.
> >>
> >> Cc: Mike Turquette <mturquette@linaro.org>
> >> Cc: Kukjin Kim <kgene.kim@samsung.com>
> >> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
> >> ---
> >>
> >> drivers/clk/Makefile | 1 +
> >> drivers/clk/samsung/Makefile | 5 +
> >> drivers/clk/samsung/clk.c | 176
> >> ++++++++++++++++++++++++++++++++++
> >> drivers/clk/samsung/clk.h | 218
> >>
> >> ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 400
> >> insertions(+), 0 deletions(-)
> >>
> >> create mode 100644 drivers/clk/samsung/Makefile
> >> create mode 100644 drivers/clk/samsung/clk.c
> >> create mode 100644 drivers/clk/samsung/clk.h
> >>
> >> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> >> index 2701235..808f8e1 100644
> >> --- a/drivers/clk/Makefile
> >> +++ b/drivers/clk/Makefile
> >> @@ -19,6 +19,7 @@ endif
> >>
> >> obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
> >> obj-$(CONFIG_ARCH_U8500) += ux500/
> >> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
> >>
> >> +obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
> >>
> >> # Chip specific
> >> obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
> >>
> >> diff --git a/drivers/clk/samsung/Makefile
> >> b/drivers/clk/samsung/Makefile new file mode 100644
> >> index 0000000..3f926b0
> >> --- /dev/null
> >> +++ b/drivers/clk/samsung/Makefile
> >> @@ -0,0 +1,5 @@
> >> +#
> >> +# Samsung Clock specific Makefile
> >> +#
> >> +
> >> +obj-$(CONFIG_PLAT_SAMSUNG) += clk.o
> >> diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
> >> new file mode 100644
> >> index 0000000..ebc6fb6
> >> --- /dev/null
> >> +++ b/drivers/clk/samsung/clk.c
> >> @@ -0,0 +1,176 @@
> >> +/*
> >> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
> >> + * Copyright (c) 2012 Linaro Ltd.
> >> + * Author: Thomas Abraham <thomas.ab@samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or
> >> modify + * it under the terms of the GNU General Public License
> >> version 2 as + * published by the Free Software Foundation.
> >> + *
> >> + * This file includes utility functions to register clocks to common
> >> + * clock framework for Samsung platforms.
> >> +*/
> >> +
> >> +#include "clk.h"
> >> +
> >> +static DEFINE_SPINLOCK(lock);
> >> +static struct clk **clk_table;
> >> +static struct clk_onecell_data clk_data;
> >> +void __iomem *reg_base;
> >
> > Shouldn't it be static?
>
> Yes, I missed that. Will fix.
>
> >> +
> >> +/* setup the essentials required to support clock lookup using ccf
> >> */
> >> +void __init samsung_clk_init(struct device_node *np, void __iomem
> >> *base, + unsigned long nr_clks)
> >> +{
> >> + reg_base = base;
> >> + if (!np)
> >> + return;
> >> +
> >> + clk_table = kzalloc(sizeof(struct clk *) * nr_clks,
> >> GFP_KERNEL);
> >> + if (!clk_table)
> >> + panic("could not allocate clock lookup table\n");
> >> +
> >> + clk_data.clks = clk_table;
> >> + clk_data.clk_num = nr_clks;
> >> + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> >> +}
> >> +
> >> +/* add a clock instance to the clock lookup table used for dt based
> >> lookup */ +void samsung_clk_add_lookup(struct clk *clk, unsigned int
> >> id) +{
> >> + if (clk_table && id)
> >
> > I'm not sure if we really need this kind of checks, but if we do, then
> > shouldn't we also check id against clk_data.clk_num to prevent out of
> > bound index?
>
> The entry into the lookup table is required only for device tree based
> platforms. And clk_table is a dynamically allocated table if booting
> with device tree support. Since the call to samsung_clk_add_lookup is
> made for non-dt platforms as well, the check for clk_table ensures
> that the entry to lookup table is done only for device tree enabled
> platforms. The check for 'id' ensures that the lookup entry index 0 is
> not used. There is no clock which has id as 0.
>
> >> + clk_table[id] = clk;
> >> +}
> >> +
> >> +/* register a list of fixed clocks */
> >> +void __init samsung_clk_register_fixed_rate(
> >> + struct samsung_fixed_rate_clock *list, unsigned int
> >> nr_clk) +{
> >> + struct clk *clk;
> >> + unsigned int idx, ret;
> >> +
> >> + for (idx = 0; idx < nr_clk; idx++, list++) {
> >> + clk = clk_register_fixed_rate(NULL, list->name,
> >> + list->parent_name, list->flags,
> >> list->fixed_rate); + if (IS_ERR(clk)) {
> >> + pr_err("%s: failed to register clock %s\n",
> >> __func__, + list->name);
> >> + continue;
> >> + }
> >> +
> >> + samsung_clk_add_lookup(clk, list->id);
> >> +
> >> + /*
> >> + * Unconditionally add a clock lookup for the fixed
> >> rate
> >
> > clocks.
> >
> >> + * There are not many of these on any of Samsung
> >> platforms. + */
> >> + ret = clk_register_clkdev(clk, list->name, NULL);
> >> + if (ret)
> >> + pr_err("%s: failed to register clock lookup for
> >> %s", + __func__, list->name);
> >> + }
> >> +}
> >> +
> >> +/* register a list of mux clocks */
> >> +void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
> >> + unsigned int nr_clk)
> >> +{
> >> + struct clk *clk;
> >> + unsigned int idx, ret;
> >> +
> >> + for (idx = 0; idx < nr_clk; idx++, list++) {
> >> + clk = clk_register_mux(NULL, list->name,
> >> list->parent_names, + list->num_parents,
> >> list->flags, reg_base + list->offset, +
> >> list->shift, list->width, list->mux_flags, &lock); + if
> >> (IS_ERR(clk)) {
> >> + pr_err("%s: failed to register clock %s\n",
> >> __func__, + list->name);
> >> + continue;
> >> + }
> >> +
> >> + samsung_clk_add_lookup(clk, list->id);
> >> +
> >> + /* register a clock lookup only if a clock alias is
> >> specified>
> > */
> >
> >> + if (list->alias) {
> >> + ret = clk_register_clkdev(clk, list->alias,
> >> + list->dev_name);
> >> + if (ret)
> >> + pr_err("%s: failed to register lookup
> >> %s\n", + __func__,
> >> list->alias); + }
> >> + }
> >> +}
> >> +
> >> +/* register a list of div clocks */
> >> +void __init samsung_clk_register_div(struct samsung_div_clock *list,
> >> + unsigned int nr_clk)
> >> +{
> >> + struct clk *clk;
> >> + unsigned int idx, ret;
> >> +
> >> + for (idx = 0; idx < nr_clk; idx++, list++) {
> >> + clk = clk_register_divider(NULL, list->name, list-
> >>
> >>parent_name,
> >>
> >> + list->flags, reg_base + list->offset,
> >> list->shift, + list->width, list->div_flags,
> >> &lock);
> >> + if (IS_ERR(clk)) {
> >> + pr_err("clock: failed to register clock %s\n",
> >> + list->name);
> >> + continue;
> >> + }
> >> +
> >> + samsung_clk_add_lookup(clk, list->id);
> >> +
> >> + /* register a clock lookup only if a clock alias is
> >> specified>
> > */
> >
> >> + if (list->alias) {
> >> + ret = clk_register_clkdev(clk, list->alias,
> >> + list->dev_name);
> >> + if (ret)
> >> + pr_err("%s: failed to register lookup
> >> %s\n", + __func__,
> >> list->alias); + }
> >> + }
> >> +}
> >> +
> >> +/* register a list of gate clocks */
> >> +void __init samsung_clk_register_gate(struct samsung_gate_clock
> >> *list,
> >> + unsigned int nr_clk)
> >> +{
> >> + struct clk *clk;
> >> + unsigned int idx, ret;
> >> +
> >> + for (idx = 0; idx < nr_clk; idx++, list++) {
> >> + clk = clk_register_gate(NULL, list->name,
> >> list->parent_name, + list->flags,
> >> reg_base + list->offset, +
> >> list->bit_idx, list->gate_flags, &lock); + if
> >> (IS_ERR(clk)) {
> >> + pr_err("clock: failed to register clock %s\n",
> >> + list->name);
> >> + continue;
> >> + }
> >> +
> >> + /* register a clock lookup only if a clock alias is
> >> specified>
> > */
> >
> >> + if (list->alias) {
> >> + ret = clk_register_clkdev(clk, list->alias,
> >> +
> >> list->dev_name);
> >> + if (ret)
> >> + pr_err("%s: failed to register lookup
> >> %s\n", + __func__, list->alias);
> >> + }
> >> +
> >> + samsung_clk_add_lookup(clk, list->id);
> >> + }
> >> +}
> >> +
> >> +/* utility function to get the rate of a specified clock */
> >> +unsigned long _get_rate(const char *clk_name)
> >> +{
> >> + struct clk *clk;
> >> + unsigned long rate;
> >> +
> >> + clk = clk_get(NULL, clk_name);
> >> + if (IS_ERR(clk))
> >> + return 0;
> >> + rate = clk_get_rate(clk);
> >> + clk_put(clk);
> >> + return rate;
> >> +}
> >> diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
> >> new file mode 100644
> >> index 0000000..ab43498
> >> --- /dev/null
> >> +++ b/drivers/clk/samsung/clk.h
> >> @@ -0,0 +1,218 @@
> >> +/*
> >> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
> >> + * Copyright (c) 2012 Linaro Ltd.
> >> + * Author: Thomas Abraham <thomas.ab@samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or
> >> modify + * it under the terms of the GNU General Public License
> >> version 2 as + * published by the Free Software Foundation.
> >> + *
> >> + * Common Clock Framework support for all Samsung platforms
> >> +*/
> >> +
> >> +#ifndef __SAMSUNG_CLK_H
> >> +#define __SAMSUNG_CLK_H
> >> +
> >> +#include <linux/clk.h>
> >> +#include <linux/clkdev.h>
> >> +#include <linux/io.h>
> >> +#include <linux/clk-provider.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_address.h>
> >> +
> >> +#include <mach/map.h>
> >> +
> >> +/**
> >> + * struct samsung_fixed_rate_clock: information about fixed-rate
> >> clock
> >> + * @id: platform specific id of the clock.
> >> + * @name: name of this fixed-rate clock.
> >> + * @parent_name: optional parent clock name.
> >> + * @flags: optional fixed-rate clock flags.
> >> + * @fixed-rate: fixed clock rate of this clock.
> >> + */
> >> +struct samsung_fixed_rate_clock {
> >> + unsigned int id;
> >> + char *name;
> >
> > Shouldn't it be const char *name?
>
> Yes, I will fix this.
>
> >> + const char *parent_name;
> >> + unsigned long flags;
> >> + unsigned long fixed_rate;
> >> +};
> >> +
> >> +#define FRATE(_id, cname, pname, f, frate) \
> >> + { \
> >> + .id = _id, \
> >> + .name = cname, \
> >> + .parent_name = pname, \
> >> + .flags = f, \
> >> + .fixed_rate = frate, \
> >> + }
> >> +
> >> +/**
> >> + * struct samsung_mux_clock: information about mux clock
> >> + * @id: platform specific id of the clock.
> >> + * @dev_name: name of the device to which this clock belongs.
> >> + * @name: name of this mux clock.
> >> + * @parent_names: array of pointer to parent clock names.
> >> + * @num_parents: number of parents listed in @parent_names.
> >> + * @flags: optional flags for basic clock.
> >> + * @offset: offset of the register for configuring the mux.
> >> + * @shift: starting bit location of the mux control bit-field in
> >> @reg.
> >> + * @width: width of the mux control bit-field in @reg.
> >> + * @mux_flags: flags for mux-type clock.
> >> + * @alias: optional clock alias name to be assigned to this clock.
> >> + */
> >> +struct samsung_mux_clock {
> >> + const unsigned int id;
> >
> > Is const unsigned int really correct?
>
> Sorry, I did not get the problem here.
Basically this const does not give us anything, while it could make
problems in future.
Let's say that one would want to register a clock in runtime, dynamically
allocating a samsung_*_clock structure. It wouldn't be possible, because
he wouldn't be able to set the id field.
Instead of making particular fields in the structures constant, I would
prefer making the arrays of these structures constant, as they are
statically initialized anyway.
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
SW Solution Development, Linux Platform
^ 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