* Re: [PATCH] regulator: provide dummy supply support
From: Mark Brown @ 2011-10-28 21:57 UTC (permalink / raw)
To: Sascha Hauer
Cc: linux-kernel, Liam Girdwood, Linus Walleij, Paul Mundt,
Tony Lindgren, Mike Frysinger, linux-sh, linux-omap,
uclinux-dist-devel
In-Reply-To: <1319833618-25190-1-git-send-email-s.hauer@pengutronix.de>
On Fri, Oct 28, 2011 at 10:26:57PM +0200, Sascha Hauer wrote:
> The following patch allows it for boards to register a dummy supply for
> devices for which no software controllable regulator is available. The
> current CONFIG_REGULATOR_DUMMY and (unused) regulator_use_dummy_regulator()
Please don't send cover letters for single patch serieses, if there's
content it should probably be in the changelog...
^ permalink raw reply
* Re: [PATCH 2/2 v3] net/smsc911x: Add regulator support
From: Sascha Hauer @ 2011-10-28 20:33 UTC (permalink / raw)
To: Linus Walleij
Cc: netdev, Steve Glendinning, Mathieu Poirer, Robert Marklund,
Paul Mundt, linux-sh, Tony Lindgren, linux-omap, Mike Frysinger,
uclinux-dist-devel, Linus Walleij
In-Reply-To: <1319719691-15799-1-git-send-email-linus.walleij@stericsson.com>
Hi Linus,
On Thu, Oct 27, 2011 at 02:48:11PM +0200, Linus Walleij wrote:
> From: Robert Marklund <robert.marklund@stericsson.com>
>
> Add some basic regulator support for the power pins, as needed
> by the ST-Ericsson Snowball platform that powers up the SMSC911
> chip using an external regulator.
>
> Platforms that use regulators and the smsc911x and have no defined
> regulator for the smsc911x and claim complete regulator
> constraints with no dummy regulators will need to provide it, for
> example using a fixed voltage regulator. It appears that this may
> affect (apart from Ux500 Snowball) possibly these archs/machines
> that from some grep:s appear to define both CONFIG_SMSC911X and
> CONFIG_REGULATOR:
>
> - ARM Freescale mx3 and OMAP 2 plus, Raumfeld machines
> - Blackfin
> - Super-H
>
...
>
> +
> +/*
> + * Request or free resources, currently just regulators.
> + *
> + * The SMSC911x has two power pins: vddvario and vdd33a, in designs where
> + * these are not always-on we need to request regulators to be turned on
> + * before we can try to access the device registers.
> + */
> +static int smsc911x_request_free_resources(struct platform_device *pdev,
> + bool request)
I had to look twice at this function name. First I thought "request the
free resources?", which other resources would you request if not the
free ones? I think it would be nicer to have two functions instead.
Just my 2 cents.
Sascha
--
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] regulator: Provide dummy supply support
From: Sascha Hauer @ 2011-10-28 20:26 UTC (permalink / raw)
To: linux-kernel
Cc: Liam Girdwood, Mark Brown, Linus Walleij, Paul Mundt,
Tony Lindgren, Mike Frysinger, linux-sh, linux-omap,
uclinux-dist-devel, Sascha Hauer
In-Reply-To: <1319833618-25190-1-git-send-email-s.hauer@pengutronix.de>
Currently we have CONFIG_REGULATOR_DUMMY which provides a fallback
dummy regulator if none is found. Enabling this option shadows
real regulator_get errors though and can't be used in production.
Also there is regulator_use_dummy_regulator() which has the
same behaviour but can be used during runtime.
This patch allows a board to register dummy supplies for devices
which need a regulator but which is not software controllable
on this board.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/regulator/Makefile | 2 +-
drivers/regulator/dummy-supply.c | 88 +++++++++++++++++++++++++++++++++++++
include/linux/regulator/machine.h | 18 ++++++++
3 files changed, 107 insertions(+), 1 deletions(-)
create mode 100644 drivers/regulator/dummy-supply.c
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 040d5aa..ff618b9 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -3,7 +3,7 @@
#
-obj-$(CONFIG_REGULATOR) += core.o dummy.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o dummy-supply.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
diff --git a/drivers/regulator/dummy-supply.c b/drivers/regulator/dummy-supply.c
new file mode 100644
index 0000000..4e62b1f
--- /dev/null
+++ b/drivers/regulator/dummy-supply.c
@@ -0,0 +1,88 @@
+/*
+ * dummy-supply.c
+ *
+ * Copyright 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This is useful for systems with mixed controllable and
+ * non-controllable regulators, as well as for allowing testing on
+ * systems with no controllable regulators.
+ */
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+struct dummy_regulator {
+ struct regulator_desc desc;
+ struct regulator_init_data initdata;
+ struct regulator_dev *rdev;
+};
+
+static struct regulator_ops dummy_ops;
+
+/**
+ * regulator_register_dummy - register a dummy supply
+ *
+ * Calling this function will register a dummy regulator
+ * for devices for which no software controllable regulator
+ * is available.
+ */
+struct dummy_regulator *regulator_register_dummy(
+ struct regulator_consumer_supply *__supply,
+ int num_supplies)
+{
+ struct dummy_regulator *dummy;
+ struct regulator_consumer_supply *supply;
+
+ dummy = kzalloc(sizeof(*dummy), GFP_KERNEL);
+ if (!dummy)
+ return NULL;
+
+ dummy->desc.name = "dummy";
+ dummy->desc.id = -1;
+ dummy->desc.type = REGULATOR_VOLTAGE;
+ dummy->desc.owner = THIS_MODULE;
+ dummy->desc.ops = &dummy_ops;
+
+ supply = kzalloc(sizeof(*supply) * num_supplies, GFP_KERNEL);
+ if (!supply)
+ goto err_alloc;
+ memcpy(supply, __supply, sizeof(*supply) * num_supplies);
+
+ dummy->initdata.num_consumer_supplies = num_supplies;
+ dummy->initdata.consumer_supplies = supply,
+
+ dummy->rdev = regulator_register(&dummy->desc, NULL,
+ &dummy->initdata, NULL);
+ if (!dummy->rdev)
+ goto err_register;
+
+ return dummy;
+
+err_register:
+ kfree(supply);
+err_alloc:
+ kfree(dummy);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(regulator_register_dummy);
+
+/**
+ * regulator_unregister_dummy - unregister a dummy supply
+ *
+ * This function unregisters a supply previously registered
+ * with regulator_register_dummy.
+ */
+void regulator_unregister_dummy(struct dummy_regulator *dummy)
+{
+ regulator_unregister(dummy->rdev);
+ kfree(dummy->initdata.consumer_supplies);
+ kfree(dummy);
+}
+EXPORT_SYMBOL_GPL(regulator_unregister_dummy);
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index ce3127a..13245cb 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -186,12 +186,20 @@ struct regulator_init_data {
void *driver_data; /* core does not touch this */
};
+/**
+ * cookie for regulator_register_dummy
+ */
+struct dummy_regulator;
+
int regulator_suspend_prepare(suspend_state_t state);
int regulator_suspend_finish(void);
#ifdef CONFIG_REGULATOR
void regulator_has_full_constraints(void);
void regulator_use_dummy_regulator(void);
+struct dummy_regulator *regulator_register_dummy(
+ struct regulator_consumer_supply *, int);
+void regulator_unregister_dummy(struct dummy_regulator *);
#else
static inline void regulator_has_full_constraints(void)
{
@@ -200,6 +208,16 @@ static inline void regulator_has_full_constraints(void)
static inline void regulator_use_dummy_regulator(void)
{
}
+
+static inline struct dummy_regulator *regulator_register_dummy(
+ struct regulator_consumer_supply *, int)
+{
+ return (void *)-1;
+};
+
+void regulator_unregister_dummy(struct dummy_regulator *)
+{
+}
#endif
#endif
--
1.7.7
^ permalink raw reply related
* [PATCH] regulator: provide dummy supply support
From: Sascha Hauer @ 2011-10-28 20:26 UTC (permalink / raw)
To: linux-kernel
Cc: Liam Girdwood, Mark Brown, Linus Walleij, Paul Mundt,
Tony Lindgren, Mike Frysinger, linux-sh, linux-omap,
uclinux-dist-devel
Hi,
The following patch allows it for boards to register a dummy supply for
devices for which no software controllable regulator is available. The
current CONFIG_REGULATOR_DUMMY and (unused) regulator_use_dummy_regulator()
mechanisms only allow to provide a dummy regulator for *all* devices
for which no regulator is found. This would shadow real errors and thus
is not really an option for production kernels.
This patch may eventually superseed the current all-or-nothing approach.
This came to me while looking over Linus' smsc911x regulator support
patch and so I added all people affected by this patch to Cc.
Sascha
^ permalink raw reply
* Re: [PATCH v9 2/4] cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
From: Arjan van de Ven @ 2011-10-28 14:24 UTC (permalink / raw)
To: Deepthi Dharwar
Cc: khilman, venki, ak, len.brown, peterz, linux-pm, linux-kernel,
linux-acpi, linux-sh, linux-pm, linux-omap, linux-arm-kernel
In-Reply-To: <20111028105020.7520.68014.stgit@localhost6.localdomain6>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 10/28/2011 3:50 AM, Deepthi Dharwar wrote:
> The cpuidle_device->prepare() mechanism causes updates to the
> cpuidle_state[].flags, setting and clearing CPUIDLE_FLAG_IGNORE
> to tell the governor not to chose a state on a per-cpu basis at
> run-time. State demotion is now handled by the driver and it returns
> the actual state entered. Hence, this mechanism is not required.
> Also this removes per-cpu flags from cpuidle_state enabling
> it to be made global.
>
having worked on some newer platforms....
this one is really still needed. doing this inside the actual states
does not work,
because if the deepest 3 states are invalid, the same (somewhat
expensive) test would have to be done 3 times,
and each of the states would have to fail before the 4th one gets chosen.
that's just not going to work
(in the state handler you can't know what other state to fall back to,
and especially not how to enter such a fallback state)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
iQEcBAEBAgAGBQJOqrsGAAoJEEHdSxh4DVnEu7EH/i5lEJctBAIubJOcZz/tvBFp
XYmAe/HqNtSXeHOVsJkTf8y4ppE8487exF7xxMik4GRN0CZNCtkyMezqDVu+eDim
O/UUbScsAc5cSY6mkjOFXLFup+mi1nkRUnAbxXEyTMhWwcbfr2OvcuO7l7TmATML
hu87P3PVEafEop3q2+uWMc57fFxnNFfEDqRx6N9V+OJKV5dHrRYL4G4E01fYGFLo
xTR0IW7nB15L0C29zk9uk/Dqow8SoJZA83c7p7AieP5zdntb6p7noIf03qmdp19f
fulwMwembCHivo+pLO+jAMhKD1T6VYoCyiYW0LHrQ2E07fayBhFJCxlazgKFcl0=FL6o
-----END PGP SIGNATURE-----
^ permalink raw reply
* Hi
From: lisa hedstrand @ 2011-10-28 11:32 UTC (permalink / raw)
To: linux-sh
My name is Miss Lisa Please accept my apology if my mode of contacting you will in any way offend you. I am compelled to contact you via this medium because i needed a friend from that part of the world. We will get to know each other in details if my proposition accepted. l am a student in UK but originally from USA.
^ permalink raw reply
* [PATCH v9 0/4] cpuidle: Global registration of idle states with
From: Deepthi Dharwar @ 2011-10-28 10:54 UTC (permalink / raw)
To: khilman, venki, ak, len.brown, peterz, rjw, santosh.shilimkar,
arjan, lenb
Cc: linux-pm, linux-sh, linux-kernel, linux-acpi, linux-pm,
linux-omap, linux-arm-kernel
Version 6 of this patch series dated 22nd Sept 2011 was
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com> for OMAP specific parts.
Reviewed-by: Kevin Hilman <khilman@ti.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Hi Len,
Can you please queue this series for the next mainline merge window by merging
it into your development tree and also linux-next for further testing.
I have also tested it by applying these patches on your ACPI tree hosted @github.
Thanks
-Deepthi
--
The following patch series implements global registration of cpuidle
states, and also has the necessary data structure changes to
accommodate the per-cpu writable members of the cpuidle_states
structure.
This patch series had been in discussion earlier and
following are the links to the previous discussions.
v8 --> https://lkml.org/lkml/2011/10/3/52
v7 --> https://lkml.org/lkml/2011/9/27/74
v6 --> https://lkml.org/lkml/2011/9/22/58
v5 --> https://lkml.org/lkml/2011/6/6/259
v4 --> https://lkml.org/lkml/2011/4/28/312
v3 --> https://lkml.org/lkml/2011/2/8/73
v2 --> https://lkml.org/lkml/2011/1/13/98
v1 --> https://lkml.org/lkml/2011/3/22/161
Changes from previous version (v8):
1. Rebased and tested on 3.1
Tests done:
1. Compile tested for ARM using the following configs: da8xx_omapl_defconfig,
kirkwood_defconfig, omap2plus_defconfig, at91rm9200_defconfig
2. Boot tested on x86 nehalem with multiple C-states for both intel_idle
and acpi_idle drivers.
3. Boot tested on T60p thinkpad that has T2600 cpu with multiple C-states.
Also tested the case when there is dynamic changes in C-states
AC <-> Battery Power switch.
Brief description of the patches:
Core change in this series is to split the cpuidle_device structure
into two parts, i.e global and per-cpu basis.
The per-cpu pieces are mostly generic statistics that can be independent
of current running driver. As a result of these changes, there is single
copy of cpuidle_states structure and single registration done by one
cpu. The low level driver is free to set per-cpu driver data on
each cpu if needed using the cpuidle_set_statedata() as the case
today. Only in very rare cases asymmetric C-states exist which can be
handled within the cpuidle driver. Most architectures do not have
asymmetric C-states.
First two patches in the series facilitate splitting of cpuidle_states
and cpuidle_device structure and next two patches do the actual split,
change the API's and make existing code follow the changed API.
[1/4] - Move the idle residency accounting part from cpuidle.c to
the respective low level drivers, so that the accounting can
be accurately maintained if the driver decides to demote the
chosen (suggested) by the governor.
[2/4] - removes the cpuidle_device()->prepare API since is is not
widely used and the only use case was to allow software
demotion using CPUIDLE_FLAG_IGNORE flag. Both these
functions can be absorbed within the cpuidle back-end
driver ad hence deprecating the prepare routine and the
CPUIDLE_FLAG_IGNORE flag.
- Ref: https://lkml.org/lkml/2011/3/25/52
[3/4] - Splits the usage statistics (read/write) part out of
cpuidle_state structure, so that the states can become read
only and hence made global.
[4/4] - Most APIs will now need to pass pointer to both global
cpuidle_driver and per-cpu cpuidle_device structure.
arch/arm/mach-at91/cpuidle.c | 41 +++--
arch/arm/mach-davinci/cpuidle.c | 51 ++++---
arch/arm/mach-exynos4/cpuidle.c | 30 ++--
arch/arm/mach-kirkwood/cpuidle.c | 42 +++---
arch/arm/mach-omap2/cpuidle34xx.c | 133 +++++++++++------
arch/sh/kernel/cpu/shmobile/cpuidle.c | 28 ++--
drivers/acpi/processor_driver.c | 20 ---
drivers/acpi/processor_idle.c | 251 +++++++++++++++++++++++++++------
drivers/cpuidle/cpuidle.c | 86 ++++-------
drivers/cpuidle/driver.c | 25 +++
drivers/cpuidle/governors/ladder.c | 41 ++++-
drivers/cpuidle/governors/menu.c | 29 ++--
drivers/cpuidle/sysfs.c | 22 ++-
drivers/idle/intel_idle.c | 130 +++++++++++++----
include/acpi/processor.h | 1
include/linux/cpuidle.h | 52 ++++---
16 files changed, 650 insertions(+), 332 deletions(-)
--
-Deepthi
^ permalink raw reply
* [PATCH v9 1/4] cpuidle: Move dev->last_residency update to driver
From: Deepthi Dharwar @ 2011-10-28 10:54 UTC (permalink / raw)
To: khilman, venki, ak, len.brown, peterz, rjw, santosh.shilimkar,
arjan, lenb
Cc: linux-sh, linux-pm, linux-kernel, linux-acpi, linux-pm,
linux-omap, linux-arm-kernel
In-Reply-To: <20111028104945.7520.83828.stgit@localhost6.localdomain6>
Cpuidle governor only suggests the state to enter using the
governor->select() interface, but allows the low level driver to
override the recommended state. The actual entered state
may be different because of software or hardware demotion. Software
demotion is done by the back-end cpuidle driver and can be accounted
correctly. Current cpuidle code uses last_state field to capture the
actual state entered and based on that updates the statistics for the
state entered.
Ideally the driver enter routine should update the counters,
and it should return the state actually entered rather than the time
spent there. The generic cpuidle code should simply handle where
the counters live in the sysfs namespace, not updating the counters.
Reference:
https://lkml.org/lkml/2011/3/25/52
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-at91/cpuidle.c | 10 +++-
arch/arm/mach-davinci/cpuidle.c | 9 +++-
arch/arm/mach-exynos4/cpuidle.c | 7 ++-
arch/arm/mach-kirkwood/cpuidle.c | 12 ++++-
arch/arm/mach-omap2/cpuidle34xx.c | 67 +++++++++++++++++------------
arch/sh/kernel/cpu/shmobile/cpuidle.c | 12 +++--
drivers/acpi/processor_idle.c | 75 ++++++++++++++++++++++-----------
drivers/cpuidle/cpuidle.c | 32 +++++++-------
drivers/cpuidle/governors/ladder.c | 13 ++++++
drivers/cpuidle/governors/menu.c | 7 ++-
drivers/idle/intel_idle.c | 12 ++++-
include/linux/cpuidle.h | 7 +--
12 files changed, 164 insertions(+), 99 deletions(-)
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 1cfeac1..4696a0d 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -33,7 +33,7 @@ static struct cpuidle_driver at91_idle_driver = {
/* Actual code that puts the SoC in different idle states */
static int at91_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
struct timeval before, after;
int idle_time;
@@ -41,10 +41,10 @@ static int at91_enter_idle(struct cpuidle_device *dev,
local_irq_disable();
do_gettimeofday(&before);
- if (state = &dev->states[0])
+ if (index = 0)
/* Wait for interrupt state */
cpu_do_idle();
- else if (state = &dev->states[1]) {
+ else if (index = 1) {
asm("b 1f; .align 5; 1:");
asm("mcr p15, 0, r0, c7, c10, 4"); /* drain write buffer */
saved_lpr = sdram_selfrefresh_enable();
@@ -55,7 +55,9 @@ static int at91_enter_idle(struct cpuidle_device *dev,
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
- return idle_time;
+
+ dev->last_residency = idle_time;
+ return index;
}
/* Initialize CPU idle by registering the idle states */
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index bd59f31..ca8582a 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -78,9 +78,9 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
- struct davinci_ops *ops = cpuidle_get_statedata(state);
+ struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]);
struct timeval before, after;
int idle_time;
@@ -98,7 +98,10 @@ static int davinci_enter_idle(struct cpuidle_device *dev,
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
- return idle_time;
+
+ dev->last_residency = idle_time;
+
+ return index;
}
static int __init davinci_cpuidle_probe(struct platform_device *pdev)
diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c
index bf7e96f..ea026e7 100644
--- a/arch/arm/mach-exynos4/cpuidle.c
+++ b/arch/arm/mach-exynos4/cpuidle.c
@@ -16,7 +16,7 @@
#include <asm/proc-fns.h>
static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state);
+ int index);
static struct cpuidle_state exynos4_cpuidle_set[] = {
[0] = {
@@ -37,7 +37,7 @@ static struct cpuidle_driver exynos4_idle_driver = {
};
static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
struct timeval before, after;
int idle_time;
@@ -52,7 +52,8 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
- return idle_time;
+ dev->last_residency = idle_time;
+ return index;
}
static int __init exynos4_init_cpuidle(void)
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index f68d33f..358dd80 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -32,17 +32,17 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Actual code that puts the SoC in different idle states */
static int kirkwood_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
struct timeval before, after;
int idle_time;
local_irq_disable();
do_gettimeofday(&before);
- if (state = &dev->states[0])
+ if (index = 0)
/* Wait for interrupt state */
cpu_do_idle();
- else if (state = &dev->states[1]) {
+ else if (index = 1) {
/*
* Following write will put DDR in self refresh.
* Note that we have 256 cycles before DDR puts it
@@ -57,7 +57,11 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
local_irq_enable();
idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
(after.tv_usec - before.tv_usec);
- return idle_time;
+
+ /* Update last residency */
+ dev->last_residency = idle_time;
+
+ return index;
}
/* Initialize CPU idle by registering the idle states */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 4bf6e6e..58425c7 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -88,17 +88,19 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
/**
* omap3_enter_idle - Programs OMAP3 to enter the specified state
* @dev: cpuidle device
- * @state: The target state to be programmed
+ * @index: the index of state to be entered
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
*/
static int omap3_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
- struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
+ struct omap3_idle_statedata *cx + cpuidle_get_statedata(&dev->states[index]);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+ int idle_time;
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
@@ -113,7 +115,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
goto return_sleep_time;
/* Deny idle for C1 */
- if (state = &dev->states[0]) {
+ if (index = 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
}
@@ -122,7 +124,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
omap_sram_idle();
/* Re-allow idle for C1 */
- if (state = &dev->states[0]) {
+ if (index = 0) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
}
@@ -134,28 +136,35 @@ return_sleep_time:
local_irq_enable();
local_fiq_enable();
- return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
+ idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
+ USEC_PER_SEC;
+
+ /* Update cpuidle counters */
+ dev->last_residency = idle_time;
+
+ return index;
}
/**
* next_valid_state - Find next valid C-state
* @dev: cpuidle device
- * @state: Currently selected C-state
+ * @index: Index of currently selected c-state
*
- * If the current state is valid, it is returned back to the caller.
- * Else, this function searches for a lower c-state which is still
- * valid.
+ * If the state corresponding to index is valid, index is returned back
+ * to the caller. Else, this function searches for a lower c-state which is
+ * still valid (as defined in omap3_power_states[]) and returns its index.
*
* A state is valid if the 'valid' field is enabled and
* if it satisfies the enable_off_mode condition.
*/
-static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
- struct cpuidle_state *curr)
+static int next_valid_state(struct cpuidle_device *dev,
+ int index)
{
- struct cpuidle_state *next = NULL;
+ struct cpuidle_state *curr = &dev->states[index];
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ int next_index = -1;
if (enable_off_mode) {
mpu_deepest_state = PWRDM_POWER_OFF;
@@ -172,20 +181,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
- return curr;
+ return index;
} else {
int idx = OMAP3_NUM_STATES - 1;
/* Reach the current state starting at highest C-state */
for (; idx >= 0; idx--) {
if (&dev->states[idx] = curr) {
- next = &dev->states[idx];
+ next_index = idx;
break;
}
}
/* Should never hit this condition */
- WARN_ON(next = NULL);
+ WARN_ON(next_index = -1);
/*
* Drop to next valid state.
@@ -197,37 +206,39 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
- next = &dev->states[idx];
+ next_index = idx;
break;
}
}
/*
* C1 is always valid.
- * So, no need to check for 'next=NULL' outside this loop.
+ * So, no need to check for 'next_index = -1' outside
+ * this loop.
*/
}
- return next;
+ return next_index;
}
/**
* omap3_enter_idle_bm - Checks for any bus activity
* @dev: cpuidle device
- * @state: The target state to be programmed
+ * @index: array index of target state to be programmed
*
* This function checks for any pending activity and then programs
* the device to the specified or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
- struct cpuidle_state *new_state;
+ struct cpuidle_state *state = &dev->states[index];
+ int new_state_idx;
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
struct omap3_idle_statedata *cx;
int ret;
if (!omap3_can_sleep()) {
- new_state = dev->safe_state;
+ new_state_idx = dev->safe_state_index;
goto select_state;
}
@@ -237,7 +248,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
*/
cam_state = pwrdm_read_pwrst(cam_pd);
if (cam_state = PWRDM_POWER_ON) {
- new_state = dev->safe_state;
+ new_state_idx = dev->safe_state_index;
goto select_state;
}
@@ -264,11 +275,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);
- new_state = next_valid_state(dev, state);
+ new_state_idx = next_valid_state(dev, index);
select_state:
- dev->last_state = new_state;
- ret = omap3_enter_idle(dev, new_state);
+ ret = omap3_enter_idle(dev, new_state_idx);
/* Restore original PER state if it was modified */
if (per_next_state != per_saved_state)
@@ -339,11 +349,12 @@ int __init omap3_idle_init(void)
cpuidle_register_driver(&omap3_idle_driver);
dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+ dev->safe_state_index = -1;
/* C1 . MPU WFI + Core active */
cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
(&dev->states[0])->enter = omap3_enter_idle;
- dev->safe_state = &dev->states[0];
+ dev->safe_state_index = 0;
cx->valid = 1; /* C1 is always valid */
cx->mpu_state = PWRDM_POWER_ON;
cx->core_state = PWRDM_POWER_ON;
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index e4469e72..7be50d4c 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -25,11 +25,11 @@ static unsigned long cpuidle_mode[] = {
};
static int cpuidle_sleep_enter(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
unsigned long allowed_mode = arch_hwblk_sleep_mode();
ktime_t before, after;
- int requested_state = state - &dev->states[0];
+ int requested_state = index;
int allowed_state;
int k;
@@ -46,11 +46,13 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
*/
k = min_t(int, allowed_state, requested_state);
- dev->last_state = &dev->states[k];
before = ktime_get();
sh_mobile_call_standby(cpuidle_mode[k]);
after = ktime_get();
- return ktime_to_ns(ktime_sub(after, before)) >> 10;
+
+ dev->last_residency = (int)ktime_to_ns(ktime_sub(after, before)) >> 10;
+
+ return k;
}
static struct cpuidle_device cpuidle_dev;
@@ -84,7 +86,7 @@ void sh_mobile_setup_cpuidle(void)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
- dev->safe_state = state;
+ dev->safe_state_index = i-1;
if (sh_mobile_sleep_supported & SUSP_SH_SF) {
state = &dev->states[i++];
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 9b88f98..463cc09 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -741,22 +741,24 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
/**
* acpi_idle_enter_c1 - enters an ACPI C1 state-type
* @dev: the target CPU
- * @state: the state data
+ * @index: index of target state
*
* This is equivalent to the HALT instruction.
*/
static int acpi_idle_enter_c1(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
ktime_t kt1, kt2;
s64 idle_time;
struct acpi_processor *pr;
+ struct cpuidle_state *state = &dev->states[index];
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
pr = __this_cpu_read(processors);
+ dev->last_residency = 0;
if (unlikely(!pr))
- return 0;
+ return -EINVAL;
local_irq_disable();
@@ -764,7 +766,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
if (acpi_idle_suspend) {
local_irq_enable();
cpu_relax();
- return 0;
+ return -EINVAL;
}
lapic_timer_state_broadcast(pr, cx, 1);
@@ -773,37 +775,46 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
kt2 = ktime_get_real();
idle_time = ktime_to_us(ktime_sub(kt2, kt1));
+ /* Update device last_residency*/
+ dev->last_residency = (int)idle_time;
+
local_irq_enable();
cx->usage++;
lapic_timer_state_broadcast(pr, cx, 0);
- return idle_time;
+ return index;
}
/**
* acpi_idle_enter_simple - enters an ACPI state without BM handling
* @dev: the target CPU
- * @state: the state data
+ * @index: the index of suggested state
*/
static int acpi_idle_enter_simple(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
struct acpi_processor *pr;
+ struct cpuidle_state *state = &dev->states[index];
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
ktime_t kt1, kt2;
s64 idle_time_ns;
s64 idle_time;
pr = __this_cpu_read(processors);
+ dev->last_residency = 0;
if (unlikely(!pr))
- return 0;
-
- if (acpi_idle_suspend)
- return(acpi_idle_enter_c1(dev, state));
+ return -EINVAL;
local_irq_disable();
+ if (acpi_idle_suspend) {
+ local_irq_enable();
+ cpu_relax();
+ return -EINVAL;
+ }
+
+
if (cx->entry_method != ACPI_CSTATE_FFH) {
current_thread_info()->status &= ~TS_POLLING;
/*
@@ -815,7 +826,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
if (unlikely(need_resched())) {
current_thread_info()->status |= TS_POLLING;
local_irq_enable();
- return 0;
+ return -EINVAL;
}
}
@@ -837,6 +848,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
idle_time = idle_time_ns;
do_div(idle_time, NSEC_PER_USEC);
+ /* Update device last_residency*/
+ dev->last_residency = (int)idle_time;
+
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(idle_time_ns);
@@ -848,7 +862,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
lapic_timer_state_broadcast(pr, cx, 0);
cx->time += idle_time;
- return idle_time;
+ return index;
}
static int c3_cpu_count;
@@ -857,14 +871,15 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
/**
* acpi_idle_enter_bm - enters C3 with proper BM handling
* @dev: the target CPU
- * @state: the state data
+ * @index: the index of suggested state
*
* If BM is detected, the deepest non-C3 idle state is entered instead.
*/
static int acpi_idle_enter_bm(struct cpuidle_device *dev,
- struct cpuidle_state *state)
+ int index)
{
struct acpi_processor *pr;
+ struct cpuidle_state *state = &dev->states[index];
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
ktime_t kt1, kt2;
s64 idle_time_ns;
@@ -872,22 +887,26 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
pr = __this_cpu_read(processors);
+ dev->last_residency = 0;
if (unlikely(!pr))
- return 0;
+ return -EINVAL;
- if (acpi_idle_suspend)
- return(acpi_idle_enter_c1(dev, state));
+
+ if (acpi_idle_suspend) {
+ cpu_relax();
+ return -EINVAL;
+ }
if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
- if (dev->safe_state) {
- dev->last_state = dev->safe_state;
- return dev->safe_state->enter(dev, dev->safe_state);
+ if (dev->safe_state_index >= 0) {
+ return dev->states[dev->safe_state_index].enter(dev,
+ dev->safe_state_index);
} else {
local_irq_disable();
acpi_safe_halt();
local_irq_enable();
- return 0;
+ return -EINVAL;
}
}
@@ -904,7 +923,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (unlikely(need_resched())) {
current_thread_info()->status |= TS_POLLING;
local_irq_enable();
- return 0;
+ return -EINVAL;
}
}
@@ -954,6 +973,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
idle_time = idle_time_ns;
do_div(idle_time, NSEC_PER_USEC);
+ /* Update device last_residency*/
+ dev->last_residency = (int)idle_time;
+
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(idle_time_ns);
@@ -965,7 +987,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
lapic_timer_state_broadcast(pr, cx, 0);
cx->time += idle_time;
- return idle_time;
+ return index;
}
struct cpuidle_driver acpi_idle_driver = {
@@ -992,6 +1014,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
}
dev->cpu = pr->id;
+ dev->safe_state_index = -1;
for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
dev->states[i].name[0] = '\0';
dev->states[i].desc[0] = '\0';
@@ -1027,13 +1050,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1;
- dev->safe_state = state;
+ dev->safe_state_index = count;
break;
case ACPI_STATE_C2:
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
- dev->safe_state = state;
+ dev->safe_state_index = count;
break;
case ACPI_STATE_C3:
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 0df0141..8faf3a6 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -62,7 +62,7 @@ int cpuidle_idle_call(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
struct cpuidle_state *target_state;
- int next_state;
+ int next_state, entered_state;
if (off)
return -ENODEV;
@@ -102,26 +102,27 @@ int cpuidle_idle_call(void)
target_state = &dev->states[next_state];
- /* enter the state and update stats */
- dev->last_state = target_state;
-
trace_power_start(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle(next_state, dev->cpu);
- dev->last_residency = target_state->enter(dev, target_state);
+ entered_state = target_state->enter(dev, next_state);
trace_power_end(dev->cpu);
trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
- if (dev->last_state)
- target_state = dev->last_state;
-
- target_state->time += (unsigned long long)dev->last_residency;
- target_state->usage++;
+ if (entered_state >= 0) {
+ /* Update cpuidle counters */
+ /* This can be moved to within driver enter routine
+ * but that results in multiple copies of same code.
+ */
+ dev->states[entered_state].time ++ (unsigned long long)dev->last_residency;
+ dev->states[entered_state].usage++;
+ }
/* give the governor an opportunity to reflect on the outcome */
if (cpuidle_curr_governor->reflect)
- cpuidle_curr_governor->reflect(dev);
+ cpuidle_curr_governor->reflect(dev, entered_state);
return 0;
}
@@ -172,11 +173,10 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
+static int poll_idle(struct cpuidle_device *dev, int index)
{
ktime_t t1, t2;
s64 diff;
- int ret;
t1 = ktime_get();
local_irq_enable();
@@ -188,8 +188,9 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
if (diff > INT_MAX)
diff = INT_MAX;
- ret = (int) diff;
- return ret;
+ dev->last_residency = (int) diff;
+
+ return index;
}
static void poll_idle_init(struct cpuidle_device *dev)
@@ -248,7 +249,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
dev->states[i].time = 0;
}
dev->last_residency = 0;
- dev->last_state = NULL;
smp_wmb();
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index f62fde2..78b06d2 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -153,11 +153,24 @@ static int ladder_enable_device(struct cpuidle_device *dev)
return 0;
}
+/**
+ * ladder_reflect - update the correct last_state_idx
+ * @dev: the CPU
+ * @index: the index of actual state entered
+ */
+static void ladder_reflect(struct cpuidle_device *dev, int index)
+{
+ struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
+ if (index > 0)
+ ldev->last_state_idx = index;
+}
+
static struct cpuidle_governor ladder_governor = {
.name = "ladder",
.rating = 10,
.enable = ladder_enable_device,
.select = ladder_select_state,
+ .reflect = ladder_reflect,
.owner = THIS_MODULE,
};
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 3600f19..3c44c53 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -310,14 +310,17 @@ static int menu_select(struct cpuidle_device *dev)
/**
* menu_reflect - records that data structures need update
* @dev: the CPU
+ * @index: the index of actual entered state
*
* NOTE: it's important to be fast here because this operation will add to
* the overall exit latency.
*/
-static void menu_reflect(struct cpuidle_device *dev)
+static void menu_reflect(struct cpuidle_device *dev, int index)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
- data->needs_update = 1;
+ data->last_state_idx = index;
+ if (index >= 0)
+ data->needs_update = 1;
}
/**
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a46dddf..a1c888d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,7 +81,7 @@ static unsigned int mwait_substates;
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state);
+static int intel_idle(struct cpuidle_device *dev, int index);
static struct cpuidle_state *cpuidle_state_table;
@@ -209,12 +209,13 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
/**
* intel_idle
* @dev: cpuidle_device
- * @state: cpuidle state
+ * @index: index of cpuidle state
*
*/
-static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
+static int intel_idle(struct cpuidle_device *dev, int index)
{
unsigned long ecx = 1; /* break on interrupt flag */
+ struct cpuidle_state *state = &dev->states[index];
unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
unsigned int cstate;
ktime_t kt_before, kt_after;
@@ -256,7 +257,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state)
if (!(lapic_timer_reliable_states & (1 << (cstate))))
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
- return usec_delta;
+ /* Update cpuidle counters */
+ dev->last_residency = (int)usec_delta;
+
+ return index;
}
static void __setup_broadcast_timer(void *arg)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index b51629e..8da811b 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -42,7 +42,7 @@ struct cpuidle_state {
unsigned long long time; /* in US */
int (*enter) (struct cpuidle_device *dev,
- struct cpuidle_state *state);
+ int index);
};
/* Idle State Flags */
@@ -87,13 +87,12 @@ struct cpuidle_device {
int state_count;
struct cpuidle_state states[CPUIDLE_STATE_MAX];
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
- struct cpuidle_state *last_state;
struct list_head device_list;
struct kobject kobj;
struct completion kobj_unregister;
void *governor_data;
- struct cpuidle_state *safe_state;
+ int safe_state_index;
int (*prepare) (struct cpuidle_device *dev);
};
@@ -169,7 +168,7 @@ struct cpuidle_governor {
void (*disable) (struct cpuidle_device *dev);
int (*select) (struct cpuidle_device *dev);
- void (*reflect) (struct cpuidle_device *dev);
+ void (*reflect) (struct cpuidle_device *dev, int index);
struct module *owner;
};
^ permalink raw reply related
* [PATCH v9 2/4] cpuidle: Remove CPUIDLE_FLAG_IGNORE and dev->prepare()
From: Deepthi Dharwar @ 2011-10-28 10:54 UTC (permalink / raw)
To: khilman, venki, ak, len.brown, peterz, rjw, santosh.shilimkar,
arjan, lenb
Cc: linux-sh, linux-pm, linux-kernel, linux-acpi, linux-pm,
linux-omap, linux-arm-kernel
In-Reply-To: <20111028104945.7520.83828.stgit@localhost6.localdomain6>
The cpuidle_device->prepare() mechanism causes updates to the
cpuidle_state[].flags, setting and clearing CPUIDLE_FLAG_IGNORE
to tell the governor not to chose a state on a per-cpu basis at
run-time. State demotion is now handled by the driver and it returns
the actual state entered. Hence, this mechanism is not required.
Also this removes per-cpu flags from cpuidle_state enabling
it to be made global.
Reference:
https://lkml.org/lkml/2011/3/25/52
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
---
drivers/cpuidle/cpuidle.c | 10 ----------
drivers/cpuidle/governors/menu.c | 2 --
include/linux/cpuidle.h | 3 ---
3 files changed, 0 insertions(+), 15 deletions(-)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8faf3a6..984d178 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -83,16 +83,6 @@ int cpuidle_idle_call(void)
hrtimer_peek_ahead_timers();
#endif
- /*
- * Call the device's prepare function before calling the
- * governor's select function. ->prepare gives the device's
- * cpuidle driver a chance to update any dynamic information
- * of its cpuidle states for the current idle period, e.g.
- * state availability, latencies, residencies, etc.
- */
- if (dev->prepare)
- dev->prepare(dev);
-
/* ask the governor for the next state */
next_state = cpuidle_curr_governor->select(dev);
if (need_resched()) {
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 3c44c53..31dd287 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -288,8 +288,6 @@ static int menu_select(struct cpuidle_device *dev)
for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
struct cpuidle_state *s = &dev->states[i];
- if (s->flags & CPUIDLE_FLAG_IGNORE)
- continue;
if (s->target_residency > data->predicted_us)
continue;
if (s->exit_latency > latency_req)
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 8da811b..c6d85cf 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -47,7 +47,6 @@ struct cpuidle_state {
/* Idle State Flags */
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
-#define CPUIDLE_FLAG_IGNORE (0x100) /* ignore during this idle period */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
@@ -93,8 +92,6 @@ struct cpuidle_device {
struct completion kobj_unregister;
void *governor_data;
int safe_state_index;
-
- int (*prepare) (struct cpuidle_device *dev);
};
DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
^ permalink raw reply related
* [PATCH v9 3/4] cpuidle: Split cpuidle_state structure and move
From: Deepthi Dharwar @ 2011-10-28 10:54 UTC (permalink / raw)
To: khilman, venki, ak, len.brown, peterz, rjw, santosh.shilimkar,
arjan, lenb
Cc: linux-sh, linux-pm, linux-kernel, linux-acpi, linux-pm,
linux-omap, linux-arm-kernel
In-Reply-To: <20111028104945.7520.83828.stgit@localhost6.localdomain6>
This is the first step towards global registration of cpuidle
states. The statistics used primarily by the governor are per-cpu
and have to be split from rest of the fields inside cpuidle_state,
which would be made global i.e. single copy. The driver_data field
is also per-cpu and moved.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-davinci/cpuidle.c | 5 ++--
arch/arm/mach-omap2/cpuidle34xx.c | 13 ++++++----
drivers/acpi/processor_idle.c | 25 ++++++++++----------
drivers/cpuidle/cpuidle.c | 11 +++++----
drivers/cpuidle/sysfs.c | 19 ++++++++++-----
drivers/idle/intel_idle.c | 46 +++++++++++++++++++++++++++----------
include/linux/cpuidle.h | 25 ++++++++++++--------
7 files changed, 90 insertions(+), 54 deletions(-)
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index ca8582a..f2d2f34 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -80,7 +80,8 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
static int davinci_enter_idle(struct cpuidle_device *dev,
int index)
{
- struct davinci_ops *ops = cpuidle_get_statedata(&dev->states[index]);
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+ struct davinci_ops *ops = cpuidle_get_statedata(state_usage);
struct timeval before, after;
int idle_time;
@@ -142,7 +143,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
if (pdata->ddr2_pdown)
davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
- cpuidle_set_statedata(&device->states[1], &davinci_states[1]);
+ cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 58425c7..d3fce7b 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -97,7 +97,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
int index)
{
struct omap3_idle_statedata *cx - cpuidle_get_statedata(&dev->states[index]);
+ cpuidle_get_statedata(&dev->states_usage[index]);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
int idle_time;
@@ -160,8 +160,9 @@ return_sleep_time:
static int next_valid_state(struct cpuidle_device *dev,
int index)
{
+ struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
struct cpuidle_state *curr = &dev->states[index];
- struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+ struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
int next_index = -1;
@@ -202,7 +203,7 @@ static int next_valid_state(struct cpuidle_device *dev,
*/
idx--;
for (; idx >= 0; idx--) {
- cx = cpuidle_get_statedata(&dev->states[idx]);
+ cx = cpuidle_get_statedata(&dev->states_usage[idx]);
if ((cx->valid) &&
(cx->mpu_state >= mpu_deepest_state) &&
(cx->core_state >= core_deepest_state)) {
@@ -231,7 +232,6 @@ static int next_valid_state(struct cpuidle_device *dev,
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
int index)
{
- struct cpuidle_state *state = &dev->states[index];
int new_state_idx;
u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
struct omap3_idle_statedata *cx;
@@ -264,7 +264,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
- cx = cpuidle_get_statedata(state);
+ cx = cpuidle_get_statedata(&dev->states_usage[index]);
core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state = PWRDM_POWER_OFF) &&
@@ -318,6 +318,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
{
struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
struct cpuidle_state *state = &dev->states[idx];
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
state->exit_latency = cpuidle_params_table[idx].exit_latency;
state->target_residency = cpuidle_params_table[idx].target_residency;
@@ -326,7 +327,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
cx->valid = cpuidle_params_table[idx].valid;
sprintf(state->name, "C%d", idx + 1);
strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
- cpuidle_set_statedata(state, cx);
+ cpuidle_set_statedata(state_usage, cx);
return cx;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 463cc09..e2264d5 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -745,14 +745,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
*
* This is equivalent to the HALT instruction.
*/
-static int acpi_idle_enter_c1(struct cpuidle_device *dev,
- int index)
+static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
{
ktime_t kt1, kt2;
s64 idle_time;
struct acpi_processor *pr;
- struct cpuidle_state *state = &dev->states[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
pr = __this_cpu_read(processors);
dev->last_residency = 0;
@@ -790,12 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
* @dev: the target CPU
* @index: the index of suggested state
*/
-static int acpi_idle_enter_simple(struct cpuidle_device *dev,
- int index)
+static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index)
{
struct acpi_processor *pr;
- struct cpuidle_state *state = &dev->states[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
ktime_t kt1, kt2;
s64 idle_time_ns;
s64 idle_time;
@@ -875,12 +873,11 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
*
* If BM is detected, the deepest non-C3 idle state is entered instead.
*/
-static int acpi_idle_enter_bm(struct cpuidle_device *dev,
- int index)
+static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
{
struct acpi_processor *pr;
- struct cpuidle_state *state = &dev->states[index];
- struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+ struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
ktime_t kt1, kt2;
s64 idle_time_ns;
s64 idle_time;
@@ -1004,6 +1001,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx;
struct cpuidle_state *state;
+ struct cpuidle_state_usage *state_usage;
struct cpuidle_device *dev = &pr->power.dev;
if (!pr->flags.power_setup_done)
@@ -1026,6 +1024,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
cx = &pr->power.states[i];
state = &dev->states[count];
+ state_usage = &dev->states_usage[count];
if (!cx->valid)
continue;
@@ -1036,7 +1035,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
- cpuidle_set_statedata(state, cx);
+ cpuidle_set_statedata(state_usage, cx);
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 984d178..b1de11e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -105,9 +105,9 @@ int cpuidle_idle_call(void)
/* This can be moved to within driver enter routine
* but that results in multiple copies of same code.
*/
- dev->states[entered_state].time ++ dev->states_usage[entered_state].time + (unsigned long long)dev->last_residency;
- dev->states[entered_state].usage++;
+ dev->states_usage[entered_state].usage++;
}
/* give the governor an opportunity to reflect on the outcome */
@@ -186,8 +186,9 @@ static int poll_idle(struct cpuidle_device *dev, int index)
static void poll_idle_init(struct cpuidle_device *dev)
{
struct cpuidle_state *state = &dev->states[0];
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[0];
- cpuidle_set_statedata(state, NULL);
+ cpuidle_set_statedata(state_usage, NULL);
snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
@@ -235,8 +236,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) {
- dev->states[i].usage = 0;
- dev->states[i].time = 0;
+ dev->states_usage[i].usage = 0;
+ dev->states_usage[i].time = 0;
}
dev->last_residency = 0;
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index be7917ec..8a1ace1 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = {
struct cpuidle_state_attr {
struct attribute attr;
- ssize_t (*show)(struct cpuidle_state *, char *);
+ ssize_t (*show)(struct cpuidle_state *, \
+ struct cpuidle_state_usage *, char *);
ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
};
@@ -224,19 +225,22 @@ struct cpuidle_state_attr {
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
#define define_show_state_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+ struct cpuidle_state_usage *state_usage, char *buf) \
{ \
return sprintf(buf, "%u\n", state->_name);\
}
#define define_show_state_ull_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+ struct cpuidle_state_usage *state_usage, char *buf) \
{ \
- return sprintf(buf, "%llu\n", state->_name);\
+ return sprintf(buf, "%llu\n", state_usage->_name);\
}
#define define_show_state_str_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \
+static ssize_t show_state_##_name(struct cpuidle_state *state, \
+ struct cpuidle_state_usage *state_usage, char *buf) \
{ \
if (state->_name[0] = '\0')\
return sprintf(buf, "<null>\n");\
@@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = {
#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
+#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
static ssize_t cpuidle_state_show(struct kobject * kobj,
struct attribute * attr ,char * buf)
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
+ struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
if (cattr->show)
- ret = cattr->show(state, buf);
+ ret = cattr->show(state, state_usage, buf);
return ret;
}
@@ -323,6 +329,7 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
if (!kobj)
goto error_state;
kobj->state = &device->states[i];
+ kobj->state_usage = &device->states_usage[i];
init_completion(&kobj->kobj_unregister);
ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index a1c888d..3aa8d4c 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -109,7 +109,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "C1-NHM",
.desc = "MWAIT 0x00",
- .driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 3,
.target_residency = 6,
@@ -117,7 +116,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "C3-NHM",
.desc = "MWAIT 0x10",
- .driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
.target_residency = 80,
@@ -125,7 +123,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C3 */
.name = "C6-NHM",
.desc = "MWAIT 0x20",
- .driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.target_residency = 800,
@@ -137,7 +134,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "C1-SNB",
.desc = "MWAIT 0x00",
- .driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
.target_residency = 1,
@@ -145,7 +141,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "C3-SNB",
.desc = "MWAIT 0x10",
- .driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 211,
@@ -153,7 +148,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C3 */
.name = "C6-SNB",
.desc = "MWAIT 0x20",
- .driver_data = (void *) 0x20,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
.target_residency = 345,
@@ -161,7 +155,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C4 */
.name = "C7-SNB",
.desc = "MWAIT 0x30",
- .driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
.target_residency = 345,
@@ -173,7 +166,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C1 */
.name = "C1-ATM",
.desc = "MWAIT 0x00",
- .driver_data = (void *) 0x00,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 1,
.target_residency = 4,
@@ -181,7 +173,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C2 */
.name = "C2-ATM",
.desc = "MWAIT 0x10",
- .driver_data = (void *) 0x10,
.flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 20,
.target_residency = 80,
@@ -190,7 +181,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C4 */
.name = "C4-ATM",
.desc = "MWAIT 0x30",
- .driver_data = (void *) 0x30,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
@@ -199,13 +189,41 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = {
{ /* MWAIT C6 */
.name = "C6-ATM",
.desc = "MWAIT 0x52",
- .driver_data = (void *) 0x52,
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
.enter = &intel_idle },
};
+static int get_driver_data(int cstate)
+{
+ int driver_data;
+ switch (cstate) {
+
+ case 1: /* MWAIT C1 */
+ driver_data = 0x00;
+ break;
+ case 2: /* MWAIT C2 */
+ driver_data = 0x10;
+ break;
+ case 3: /* MWAIT C3 */
+ driver_data = 0x20;
+ break;
+ case 4: /* MWAIT C4 */
+ driver_data = 0x30;
+ break;
+ case 5: /* MWAIT C5 */
+ driver_data = 0x40;
+ break;
+ case 6: /* MWAIT C6 */
+ driver_data = 0x52;
+ break;
+ default:
+ driver_data = 0x00;
+ }
+ return driver_data;
+}
+
/**
* intel_idle
* @dev: cpuidle_device
@@ -216,7 +234,8 @@ static int intel_idle(struct cpuidle_device *dev, int index)
{
unsigned long ecx = 1; /* break on interrupt flag */
struct cpuidle_state *state = &dev->states[index];
- unsigned long eax = (unsigned long)cpuidle_get_statedata(state);
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
+ unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
unsigned int cstate;
ktime_t kt_before, kt_after;
s64 usec_delta;
@@ -451,6 +470,9 @@ static int intel_idle_cpuidle_devices_init(void)
dev->states[dev->state_count] = /* structure copy */
cpuidle_state_table[cstate];
+ dev->states_usage[dev->state_count].driver_data + (void *)get_driver_data(cstate);
+
dev->state_count += 1;
}
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index c6d85cf..0156540 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -28,19 +28,22 @@ struct cpuidle_device;
* CPUIDLE DEVICE INTERFACE *
****************************/
+struct cpuidle_state_usage {
+ void *driver_data;
+
+ unsigned long long usage;
+ unsigned long long time; /* in US */
+};
+
struct cpuidle_state {
char name[CPUIDLE_NAME_LEN];
char desc[CPUIDLE_DESC_LEN];
- void *driver_data;
unsigned int flags;
unsigned int exit_latency; /* in US */
unsigned int power_usage; /* in mW */
unsigned int target_residency; /* in US */
- unsigned long long usage;
- unsigned long long time; /* in US */
-
int (*enter) (struct cpuidle_device *dev,
int index);
};
@@ -52,26 +55,27 @@ struct cpuidle_state {
/**
* cpuidle_get_statedata - retrieves private driver state data
- * @state: the state
+ * @st_usage: the state usage statistics
*/
-static inline void * cpuidle_get_statedata(struct cpuidle_state *state)
+static inline void *cpuidle_get_statedata(struct cpuidle_state_usage *st_usage)
{
- return state->driver_data;
+ return st_usage->driver_data;
}
/**
* cpuidle_set_statedata - stores private driver state data
- * @state: the state
+ * @st_usage: the state usage statistics
* @data: the private data
*/
static inline void
-cpuidle_set_statedata(struct cpuidle_state *state, void *data)
+cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data)
{
- state->driver_data = data;
+ st_usage->driver_data = data;
}
struct cpuidle_state_kobj {
struct cpuidle_state *state;
+ struct cpuidle_state_usage *state_usage;
struct completion kobj_unregister;
struct kobject kobj;
};
@@ -85,6 +89,7 @@ struct cpuidle_device {
int last_residency;
int state_count;
struct cpuidle_state states[CPUIDLE_STATE_MAX];
+ struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
struct list_head device_list;
^ permalink raw reply related
* [PATCH v9 4/4] cpuidle: Single/Global registration of idle states
From: Deepthi Dharwar @ 2011-10-28 10:54 UTC (permalink / raw)
To: khilman, venki, ak, len.brown, peterz, rjw, santosh.shilimkar,
arjan, lenb
Cc: linux-sh, linux-pm, linux-kernel, linux-acpi, linux-pm,
linux-omap, linux-arm-kernel
In-Reply-To: <20111028104945.7520.83828.stgit@localhost6.localdomain6>
This patch makes the cpuidle_states structure global (single copy)
instead of per-cpu. The statistics needed on per-cpu basis
by the governor are kept per-cpu. This simplifies the cpuidle
subsystem as state registration is done by single cpu only.
Having single copy of cpuidle_states saves memory. Rare case
of asymmetric C-states can be handled within the cpuidle driver
and architectures such as POWER do not have asymmetric C-states.
Having single/global registration of all the idle states,
dynamic C-state transitions on x86 are handled by
the boot cpu. Here, the boot cpu would disable all the devices,
re-populate the states and later enable all the devices,
irrespective of the cpu that would receive the notification first.
Reference:
https://lkml.org/lkml/2011/4/25/83
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: Trinabh Gupta <g.trinabh@gmail.com>
Tested-by: Jean Pihet <j-pihet@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: Kevin Hilman <khilman@ti.com>
---
arch/arm/mach-at91/cpuidle.c | 31 +++--
arch/arm/mach-davinci/cpuidle.c | 39 ++++---
arch/arm/mach-exynos4/cpuidle.c | 23 ++--
arch/arm/mach-kirkwood/cpuidle.c | 30 +++--
arch/arm/mach-omap2/cpuidle34xx.c | 73 ++++++++-----
arch/sh/kernel/cpu/shmobile/cpuidle.c | 18 ++-
drivers/acpi/processor_driver.c | 20 +--
drivers/acpi/processor_idle.c | 191 +++++++++++++++++++++++++++++----
drivers/cpuidle/cpuidle.c | 45 ++------
drivers/cpuidle/driver.c | 25 ++++
drivers/cpuidle/governors/ladder.c | 28 +++--
drivers/cpuidle/governors/menu.c | 20 ++-
drivers/cpuidle/sysfs.c | 3 -
drivers/idle/intel_idle.c | 80 +++++++++++---
include/acpi/processor.h | 1
include/linux/cpuidle.h | 19 ++-
16 files changed, 439 insertions(+), 207 deletions(-)
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 4696a0d..93178f6 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -33,6 +33,7 @@ static struct cpuidle_driver at91_idle_driver = {
/* Actual code that puts the SoC in different idle states */
static int at91_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct timeval before, after;
@@ -64,27 +65,29 @@ static int at91_enter_idle(struct cpuidle_device *dev,
static int at91_init_cpuidle(void)
{
struct cpuidle_device *device;
-
- cpuidle_register_driver(&at91_idle_driver);
+ struct cpuidle_driver *driver = &at91_idle_driver;
device = &per_cpu(at91_cpuidle_device, smp_processor_id());
device->state_count = AT91_MAX_STATES;
+ driver->state_count = AT91_MAX_STATES;
/* Wait for interrupt state */
- device->states[0].enter = at91_enter_idle;
- device->states[0].exit_latency = 1;
- device->states[0].target_residency = 10000;
- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ driver->states[0].enter = at91_enter_idle;
+ driver->states[0].exit_latency = 1;
+ driver->states[0].target_residency = 10000;
+ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[0].name, "WFI");
+ strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and RAM self refresh state */
- device->states[1].enter = at91_enter_idle;
- device->states[1].exit_latency = 10;
- device->states[1].target_residency = 10000;
- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "RAM_SR");
- strcpy(device->states[1].desc, "WFI and RAM Self Refresh");
+ driver->states[1].enter = at91_enter_idle;
+ driver->states[1].exit_latency = 10;
+ driver->states[1].target_residency = 10000;
+ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[1].name, "RAM_SR");
+ strcpy(driver->states[1].desc, "WFI and RAM Self Refresh");
+
+ cpuidle_register_driver(&at91_idle_driver);
if (cpuidle_register_device(device)) {
printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index f2d2f34..dbeeccd 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -78,6 +78,7 @@ static struct davinci_ops davinci_states[DAVINCI_CPUIDLE_MAX_STATES] = {
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -109,6 +110,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
{
int ret;
struct cpuidle_device *device;
+ struct cpuidle_driver *driver = &davinci_idle_driver;
struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
@@ -120,32 +122,33 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ddr2_reg_base = pdata->ddr2_ctlr_base;
- ret = cpuidle_register_driver(&davinci_idle_driver);
- if (ret) {
- dev_err(&pdev->dev, "failed to register driver\n");
- return ret;
- }
-
/* Wait for interrupt state */
- device->states[0].enter = davinci_enter_idle;
- device->states[0].exit_latency = 1;
- device->states[0].target_residency = 10000;
- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ driver->states[0].enter = davinci_enter_idle;
+ driver->states[0].exit_latency = 1;
+ driver->states[0].target_residency = 10000;
+ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[0].name, "WFI");
+ strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and DDR self refresh state */
- device->states[1].enter = davinci_enter_idle;
- device->states[1].exit_latency = 10;
- device->states[1].target_residency = 10000;
- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "DDR SR");
- strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+ driver->states[1].enter = davinci_enter_idle;
+ driver->states[1].exit_latency = 10;
+ driver->states[1].target_residency = 10000;
+ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[1].name, "DDR SR");
+ strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
if (pdata->ddr2_pdown)
davinci_states[1].flags |= DAVINCI_CPUIDLE_FLAGS_DDR2_PWDN;
cpuidle_set_statedata(&device->states_usage[1], &davinci_states[1]);
device->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+ driver->state_count = DAVINCI_CPUIDLE_MAX_STATES;
+
+ ret = cpuidle_register_driver(&davinci_idle_driver);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register driver\n");
+ return ret;
+ }
ret = cpuidle_register_device(device);
if (ret) {
diff --git a/arch/arm/mach-exynos4/cpuidle.c b/arch/arm/mach-exynos4/cpuidle.c
index ea026e7..35f6502 100644
--- a/arch/arm/mach-exynos4/cpuidle.c
+++ b/arch/arm/mach-exynos4/cpuidle.c
@@ -16,6 +16,7 @@
#include <asm/proc-fns.h>
static int exynos4_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index);
static struct cpuidle_state exynos4_cpuidle_set[] = {
@@ -37,6 +38,7 @@ static struct cpuidle_driver exynos4_idle_driver = {
};
static int exynos4_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct timeval before, after;
@@ -60,22 +62,23 @@ static int __init exynos4_init_cpuidle(void)
{
int i, max_cpuidle_state, cpu_id;
struct cpuidle_device *device;
-
+ struct cpuidle_driver *drv = &exynos4_idle_driver;
+
+ /* Setup cpuidle driver */
+ drv->state_count = (sizeof(exynos4_cpuidle_set) /
+ sizeof(struct cpuidle_state));
+ max_cpuidle_state = drv->state_count;
+ for (i = 0; i < max_cpuidle_state; i++) {
+ memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
+ sizeof(struct cpuidle_state));
+ }
cpuidle_register_driver(&exynos4_idle_driver);
for_each_cpu(cpu_id, cpu_online_mask) {
device = &per_cpu(exynos4_cpuidle_device, cpu_id);
device->cpu = cpu_id;
- device->state_count = (sizeof(exynos4_cpuidle_set) /
- sizeof(struct cpuidle_state));
-
- max_cpuidle_state = device->state_count;
-
- for (i = 0; i < max_cpuidle_state; i++) {
- memcpy(&device->states[i], &exynos4_cpuidle_set[i],
- sizeof(struct cpuidle_state));
- }
+ device->state_count = drv->state_count;
if (cpuidle_register_device(device)) {
printk(KERN_ERR "CPUidle register device failed\n,");
diff --git a/arch/arm/mach-kirkwood/cpuidle.c b/arch/arm/mach-kirkwood/cpuidle.c
index 358dd80..ffd690d 100644
--- a/arch/arm/mach-kirkwood/cpuidle.c
+++ b/arch/arm/mach-kirkwood/cpuidle.c
@@ -32,6 +32,7 @@ static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Actual code that puts the SoC in different idle states */
static int kirkwood_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct timeval before, after;
@@ -68,28 +69,29 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
static int kirkwood_init_cpuidle(void)
{
struct cpuidle_device *device;
-
- cpuidle_register_driver(&kirkwood_idle_driver);
+ struct cpuidle_driver *driver = &kirkwood_idle_driver;
device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
device->state_count = KIRKWOOD_MAX_STATES;
+ driver->state_count = KIRKWOOD_MAX_STATES;
/* Wait for interrupt state */
- device->states[0].enter = kirkwood_enter_idle;
- device->states[0].exit_latency = 1;
- device->states[0].target_residency = 10000;
- device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[0].name, "WFI");
- strcpy(device->states[0].desc, "Wait for interrupt");
+ driver->states[0].enter = kirkwood_enter_idle;
+ driver->states[0].exit_latency = 1;
+ driver->states[0].target_residency = 10000;
+ driver->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[0].name, "WFI");
+ strcpy(driver->states[0].desc, "Wait for interrupt");
/* Wait for interrupt and DDR self refresh state */
- device->states[1].enter = kirkwood_enter_idle;
- device->states[1].exit_latency = 10;
- device->states[1].target_residency = 10000;
- device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
- strcpy(device->states[1].name, "DDR SR");
- strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
+ driver->states[1].enter = kirkwood_enter_idle;
+ driver->states[1].exit_latency = 10;
+ driver->states[1].target_residency = 10000;
+ driver->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+ strcpy(driver->states[1].name, "DDR SR");
+ strcpy(driver->states[1].desc, "WFI and DDR Self Refresh");
+ cpuidle_register_driver(&kirkwood_idle_driver);
if (cpuidle_register_device(device)) {
printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
return -EIO;
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index d3fce7b..1fe35c2 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -88,12 +88,14 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
/**
* omap3_enter_idle - Programs OMAP3 to enter the specified state
* @dev: cpuidle device
+ * @drv: cpuidle driver
* @index: the index of state to be entered
*
* Called from the CPUidle framework to program the device to the
* specified target state selected by the governor.
*/
static int omap3_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct omap3_idle_statedata *cx @@ -148,6 +150,7 @@ return_sleep_time:
/**
* next_valid_state - Find next valid C-state
* @dev: cpuidle device
+ * @drv: cpuidle driver
* @index: Index of currently selected c-state
*
* If the state corresponding to index is valid, index is returned back
@@ -158,10 +161,11 @@ return_sleep_time:
* if it satisfies the enable_off_mode condition.
*/
static int next_valid_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
- struct cpuidle_state *curr = &dev->states[index];
+ struct cpuidle_state *curr = &drv->states[index];
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
@@ -188,7 +192,7 @@ static int next_valid_state(struct cpuidle_device *dev,
/* Reach the current state starting at highest C-state */
for (; idx >= 0; idx--) {
- if (&dev->states[idx] = curr) {
+ if (&drv->states[idx] = curr) {
next_index = idx;
break;
}
@@ -224,12 +228,14 @@ static int next_valid_state(struct cpuidle_device *dev,
/**
* omap3_enter_idle_bm - Checks for any bus activity
* @dev: cpuidle device
+ * @drv: cpuidle driver
* @index: array index of target state to be programmed
*
* This function checks for any pending activity and then programs
* the device to the specified or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
int new_state_idx;
@@ -238,7 +244,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
int ret;
if (!omap3_can_sleep()) {
- new_state_idx = dev->safe_state_index;
+ new_state_idx = drv->safe_state_index;
goto select_state;
}
@@ -248,7 +254,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
*/
cam_state = pwrdm_read_pwrst(cam_pd);
if (cam_state = PWRDM_POWER_ON) {
- new_state_idx = dev->safe_state_index;
+ new_state_idx = drv->safe_state_index;
goto select_state;
}
@@ -275,10 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);
- new_state_idx = next_valid_state(dev, index);
+ new_state_idx = next_valid_state(dev, drv, index);
select_state:
- ret = omap3_enter_idle(dev, new_state_idx);
+ ret = omap3_enter_idle(dev, drv, new_state_idx);
/* Restore original PER state if it was modified */
if (per_next_state != per_saved_state)
@@ -311,22 +317,30 @@ struct cpuidle_driver omap3_idle_driver = {
.owner = THIS_MODULE,
};
-/* Helper to fill the C-state common data and register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate(
- struct cpuidle_device *dev,
+/* Helper to fill the C-state common data*/
+static inline void _fill_cstate(struct cpuidle_driver *drv,
int idx, const char *descr)
{
- struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
- struct cpuidle_state *state = &dev->states[idx];
- struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+ struct cpuidle_state *state = &drv->states[idx];
state->exit_latency = cpuidle_params_table[idx].exit_latency;
state->target_residency = cpuidle_params_table[idx].target_residency;
state->flags = CPUIDLE_FLAG_TIME_VALID;
state->enter = omap3_enter_idle_bm;
- cx->valid = cpuidle_params_table[idx].valid;
sprintf(state->name, "C%d", idx + 1);
strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
+
+}
+
+/* Helper to register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate_usage(
+ struct cpuidle_device *dev,
+ int idx)
+{
+ struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+ struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+
+ cx->valid = cpuidle_params_table[idx].valid;
cpuidle_set_statedata(state_usage, cx);
return cx;
@@ -341,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
int __init omap3_idle_init(void)
{
struct cpuidle_device *dev;
+ struct cpuidle_driver *drv = &omap3_idle_driver;
struct omap3_idle_statedata *cx;
mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -348,45 +363,52 @@ int __init omap3_idle_init(void)
per_pd = pwrdm_lookup("per_pwrdm");
cam_pd = pwrdm_lookup("cam_pwrdm");
- cpuidle_register_driver(&omap3_idle_driver);
+
+ drv->safe_state_index = -1;
dev = &per_cpu(omap3_idle_dev, smp_processor_id());
- dev->safe_state_index = -1;
/* C1 . MPU WFI + Core active */
- cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
- (&dev->states[0])->enter = omap3_enter_idle;
- dev->safe_state_index = 0;
+ _fill_cstate(drv, 0, "MPU ON + CORE ON");
+ (&drv->states[0])->enter = omap3_enter_idle;
+ drv->safe_state_index = 0;
+ cx = _fill_cstate_usage(dev, 0);
cx->valid = 1; /* C1 is always valid */
cx->mpu_state = PWRDM_POWER_ON;
cx->core_state = PWRDM_POWER_ON;
/* C2 . MPU WFI + Core inactive */
- cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+ _fill_cstate(drv, 1, "MPU ON + CORE ON");
+ cx = _fill_cstate_usage(dev, 1);
cx->mpu_state = PWRDM_POWER_ON;
cx->core_state = PWRDM_POWER_ON;
/* C3 . MPU CSWR + Core inactive */
- cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+ _fill_cstate(drv, 2, "MPU RET + CORE ON");
+ cx = _fill_cstate_usage(dev, 2);
cx->mpu_state = PWRDM_POWER_RET;
cx->core_state = PWRDM_POWER_ON;
/* C4 . MPU OFF + Core inactive */
- cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+ _fill_cstate(drv, 3, "MPU OFF + CORE ON");
+ cx = _fill_cstate_usage(dev, 3);
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_ON;
/* C5 . MPU RET + Core RET */
- cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+ _fill_cstate(drv, 4, "MPU RET + CORE RET");
+ cx = _fill_cstate_usage(dev, 4);
cx->mpu_state = PWRDM_POWER_RET;
cx->core_state = PWRDM_POWER_RET;
/* C6 . MPU OFF + Core RET */
- cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+ _fill_cstate(drv, 5, "MPU OFF + CORE RET");
+ cx = _fill_cstate_usage(dev, 5);
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_RET;
/* C7 . MPU OFF + Core OFF */
- cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+ _fill_cstate(drv, 6, "MPU OFF + CORE OFF");
+ cx = _fill_cstate_usage(dev, 6);
/*
* Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
* enable OFF mode in a stable form for previous revisions.
@@ -400,6 +422,9 @@ int __init omap3_idle_init(void)
cx->mpu_state = PWRDM_POWER_OFF;
cx->core_state = PWRDM_POWER_OFF;
+ drv->state_count = OMAP3_NUM_STATES;
+ cpuidle_register_driver(&omap3_idle_driver);
+
dev->state_count = OMAP3_NUM_STATES;
if (cpuidle_register_device(dev)) {
printk(KERN_ERR "%s: CPUidle register device failed\n",
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 7be50d4c..ad1012a 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -25,6 +25,7 @@ static unsigned long cpuidle_mode[] = {
};
static int cpuidle_sleep_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index)
{
unsigned long allowed_mode = arch_hwblk_sleep_mode();
@@ -64,19 +65,19 @@ static struct cpuidle_driver cpuidle_driver = {
void sh_mobile_setup_cpuidle(void)
{
struct cpuidle_device *dev = &cpuidle_dev;
+ struct cpuidle_driver *drv = &cpuidle_driver;
struct cpuidle_state *state;
int i;
- cpuidle_register_driver(&cpuidle_driver);
for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
- dev->states[i].name[0] = '\0';
- dev->states[i].desc[0] = '\0';
+ drv->states[i].name[0] = '\0';
+ drv->states[i].desc[0] = '\0';
}
i = CPUIDLE_DRIVER_STATE_START;
- state = &dev->states[i++];
+ state = &drv->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
state->exit_latency = 1;
@@ -86,10 +87,10 @@ void sh_mobile_setup_cpuidle(void)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
- dev->safe_state_index = i-1;
+ drv->safe_state_index = i-1;
if (sh_mobile_sleep_supported & SUSP_SH_SF) {
- state = &dev->states[i++];
+ state = &drv->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
strncpy(state->desc, "SuperH Sleep Mode [SF]",
CPUIDLE_DESC_LEN);
@@ -102,7 +103,7 @@ void sh_mobile_setup_cpuidle(void)
}
if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
- state = &dev->states[i++];
+ state = &drv->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
CPUIDLE_DESC_LEN);
@@ -114,7 +115,10 @@ void sh_mobile_setup_cpuidle(void)
state->enter = cpuidle_sleep_enter;
}
+ drv->state_count = i;
dev->state_count = i;
+ cpuidle_register_driver(&cpuidle_driver);
+
cpuidle_register_device(dev);
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index a4e0f1b..9d7bc9f 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -426,7 +426,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
if (action = CPU_ONLINE && pr) {
acpi_processor_ppc_has_changed(pr, 0);
- acpi_processor_cst_has_changed(pr);
+ acpi_processor_hotplug(pr);
acpi_processor_reevaluate_tstate(pr, action);
acpi_processor_tstate_has_changed(pr);
}
@@ -503,8 +503,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
acpi_processor_get_throttling_info(pr);
acpi_processor_get_limit_info(pr);
-
- if (cpuidle_get_driver() = &acpi_idle_driver)
+ if (!cpuidle_get_driver() || cpuidle_get_driver() = &acpi_idle_driver)
acpi_processor_power_init(pr, device);
pr->cdev = thermal_cooling_device_register("Processor", device,
@@ -800,17 +799,9 @@ static int __init acpi_processor_init(void)
memset(&errata, 0, sizeof(errata));
- if (!cpuidle_register_driver(&acpi_idle_driver)) {
- printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
- acpi_idle_driver.name);
- } else {
- printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n",
- cpuidle_get_driver()->name);
- }
-
result = acpi_bus_register_driver(&acpi_processor_driver);
if (result < 0)
- goto out_cpuidle;
+ return result;
acpi_processor_install_hotplug_notify();
@@ -821,11 +812,6 @@ static int __init acpi_processor_init(void)
acpi_processor_throttling_init();
return 0;
-
-out_cpuidle:
- cpuidle_unregister_driver(&acpi_idle_driver);
-
- return result;
}
static void __exit acpi_processor_exit(void)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e2264d5..73b2909 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -741,11 +741,13 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
/**
* acpi_idle_enter_c1 - enters an ACPI C1 state-type
* @dev: the target CPU
+ * @drv: cpuidle driver containing cpuidle state info
* @index: index of target state
*
* This is equivalent to the HALT instruction.
*/
-static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_c1(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
ktime_t kt1, kt2;
s64 idle_time;
@@ -787,9 +789,11 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, int index)
/**
* acpi_idle_enter_simple - enters an ACPI state without BM handling
* @dev: the target CPU
+ * @drv: cpuidle driver with cpuidle state information
* @index: the index of suggested state
*/
-static int acpi_idle_enter_simple(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_simple(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -869,11 +873,13 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
/**
* acpi_idle_enter_bm - enters C3 with proper BM handling
* @dev: the target CPU
+ * @drv: cpuidle driver containing state data
* @index: the index of suggested state
*
* If BM is detected, the deepest non-C3 idle state is entered instead.
*/
-static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
+static int acpi_idle_enter_bm(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
@@ -896,9 +902,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, int index)
}
if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
- if (dev->safe_state_index >= 0) {
- return dev->states[dev->safe_state_index].enter(dev,
- dev->safe_state_index);
+ if (drv->safe_state_index >= 0) {
+ return drv->states[drv->safe_state_index].enter(dev,
+ drv, drv->safe_state_index);
} else {
local_irq_disable();
acpi_safe_halt();
@@ -993,14 +999,15 @@ struct cpuidle_driver acpi_idle_driver = {
};
/**
- * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE
+ * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE
+ * device i.e. per-cpu data
+ *
* @pr: the ACPI processor
*/
-static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
+static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
{
int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx;
- struct cpuidle_state *state;
struct cpuidle_state_usage *state_usage;
struct cpuidle_device *dev = &pr->power.dev;
@@ -1012,18 +1019,12 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
}
dev->cpu = pr->id;
- dev->safe_state_index = -1;
- for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
- dev->states[i].name[0] = '\0';
- dev->states[i].desc[0] = '\0';
- }
if (max_cstate = 0)
max_cstate = 1;
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
cx = &pr->power.states[i];
- state = &dev->states[count];
state_usage = &dev->states_usage[count];
if (!cx->valid)
@@ -1035,8 +1036,64 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
+
cpuidle_set_statedata(state_usage, cx);
+ count++;
+ if (count = CPUIDLE_STATE_MAX)
+ break;
+ }
+
+ dev->state_count = count;
+
+ if (!count)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * acpi_processor_setup_cpuidle states- prepares and configures cpuidle
+ * global state data i.e. idle routines
+ *
+ * @pr: the ACPI processor
+ */
+static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
+{
+ int i, count = CPUIDLE_DRIVER_STATE_START;
+ struct acpi_processor_cx *cx;
+ struct cpuidle_state *state;
+ struct cpuidle_driver *drv = &acpi_idle_driver;
+
+ if (!pr->flags.power_setup_done)
+ return -EINVAL;
+
+ if (pr->flags.power = 0)
+ return -EINVAL;
+
+ drv->safe_state_index = -1;
+ for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+ drv->states[i].name[0] = '\0';
+ drv->states[i].desc[0] = '\0';
+ }
+
+ if (max_cstate = 0)
+ max_cstate = 1;
+
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
+ cx = &pr->power.states[i];
+
+ if (!cx->valid)
+ continue;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
+ !pr->flags.has_cst &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
+ continue;
+#endif
+
+ state = &drv->states[count];
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
state->exit_latency = cx->latency;
@@ -1049,13 +1106,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1;
- dev->safe_state_index = count;
+ drv->safe_state_index = count;
break;
case ACPI_STATE_C2:
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
- dev->safe_state_index = count;
+ drv->safe_state_index = count;
break;
case ACPI_STATE_C3:
@@ -1071,7 +1128,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
break;
}
- dev->state_count = count;
+ drv->state_count = count;
if (!count)
return -EINVAL;
@@ -1079,7 +1136,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
return 0;
}
-int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+int acpi_processor_hotplug(struct acpi_processor *pr)
{
int ret = 0;
@@ -1100,7 +1157,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
cpuidle_disable_device(&pr->power.dev);
acpi_processor_get_power_info(pr);
if (pr->flags.power) {
- acpi_processor_setup_cpuidle(pr);
+ acpi_processor_setup_cpuidle_cx(pr);
ret = cpuidle_enable_device(&pr->power.dev);
}
cpuidle_resume_and_unlock();
@@ -1108,10 +1165,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
return ret;
}
+int acpi_processor_cst_has_changed(struct acpi_processor *pr)
+{
+ int cpu;
+ struct acpi_processor *_pr;
+
+ if (disabled_by_idle_boot_param())
+ return 0;
+
+ if (!pr)
+ return -EINVAL;
+
+ if (nocst)
+ return -ENODEV;
+
+ if (!pr->flags.power_setup_done)
+ return -ENODEV;
+
+ /*
+ * FIXME: Design the ACPI notification to make it once per
+ * system instead of once per-cpu. This condition is a hack
+ * to make the code that updates C-States be called once.
+ */
+
+ if (smp_processor_id() = 0 &&
+ cpuidle_get_driver() = &acpi_idle_driver) {
+
+ cpuidle_pause_and_lock();
+ /* Protect against cpu-hotplug */
+ get_online_cpus();
+
+ /* Disable all cpuidle devices */
+ for_each_online_cpu(cpu) {
+ _pr = per_cpu(processors, cpu);
+ if (!_pr || !_pr->flags.power_setup_done)
+ continue;
+ cpuidle_disable_device(&_pr->power.dev);
+ }
+
+ /* Populate Updated C-state information */
+ acpi_processor_setup_cpuidle_states(pr);
+
+ /* Enable all cpuidle devices */
+ for_each_online_cpu(cpu) {
+ _pr = per_cpu(processors, cpu);
+ if (!_pr || !_pr->flags.power_setup_done)
+ continue;
+ acpi_processor_get_power_info(_pr);
+ if (_pr->flags.power) {
+ acpi_processor_setup_cpuidle_cx(_pr);
+ cpuidle_enable_device(&_pr->power.dev);
+ }
+ }
+ put_online_cpus();
+ cpuidle_resume_and_unlock();
+ }
+
+ return 0;
+}
+
+static int acpi_processor_registered;
+
int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
{
acpi_status status = 0;
+ int retval;
static int first_run;
if (disabled_by_idle_boot_param())
@@ -1148,9 +1267,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
* platforms that only support C1.
*/
if (pr->flags.power) {
- acpi_processor_setup_cpuidle(pr);
- if (cpuidle_register_device(&pr->power.dev))
- return -EIO;
+ /* Register acpi_idle_driver if not already registered */
+ if (!acpi_processor_registered) {
+ acpi_processor_setup_cpuidle_states(pr);
+ retval = cpuidle_register_driver(&acpi_idle_driver);
+ if (retval)
+ return retval;
+ printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n",
+ acpi_idle_driver.name);
+ }
+ /* Register per-cpu cpuidle_device. Cpuidle driver
+ * must already be registered before registering device
+ */
+ acpi_processor_setup_cpuidle_cx(pr);
+ retval = cpuidle_register_device(&pr->power.dev);
+ if (retval) {
+ if (acpi_processor_registered = 0)
+ cpuidle_unregister_driver(&acpi_idle_driver);
+ return retval;
+ }
+ acpi_processor_registered++;
}
return 0;
}
@@ -1161,8 +1297,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
if (disabled_by_idle_boot_param())
return 0;
- cpuidle_unregister_device(&pr->power.dev);
- pr->flags.power_setup_done = 0;
+ if (pr->flags.power) {
+ cpuidle_unregister_device(&pr->power.dev);
+ acpi_processor_registered--;
+ if (acpi_processor_registered = 0)
+ cpuidle_unregister_driver(&acpi_idle_driver);
+ }
+ pr->flags.power_setup_done = 0;
return 0;
}
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index b1de11e..1040bc9 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -61,6 +61,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev);
int cpuidle_idle_call(void)
{
struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+ struct cpuidle_driver *drv = cpuidle_get_driver();
struct cpuidle_state *target_state;
int next_state, entered_state;
@@ -84,18 +85,18 @@ int cpuidle_idle_call(void)
#endif
/* ask the governor for the next state */
- next_state = cpuidle_curr_governor->select(dev);
+ next_state = cpuidle_curr_governor->select(drv, dev);
if (need_resched()) {
local_irq_enable();
return 0;
}
- target_state = &dev->states[next_state];
+ target_state = &drv->states[next_state];
trace_power_start(POWER_CSTATE, next_state, dev->cpu);
trace_cpu_idle(next_state, dev->cpu);
- entered_state = target_state->enter(dev, next_state);
+ entered_state = target_state->enter(dev, drv, next_state);
trace_power_end(dev->cpu);
trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu);
@@ -163,7 +164,8 @@ void cpuidle_resume_and_unlock(void)
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
-static int poll_idle(struct cpuidle_device *dev, int index)
+static int poll_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
ktime_t t1, t2;
s64 diff;
@@ -183,12 +185,9 @@ static int poll_idle(struct cpuidle_device *dev, int index)
return index;
}
-static void poll_idle_init(struct cpuidle_device *dev)
+static void poll_idle_init(struct cpuidle_driver *drv)
{
- struct cpuidle_state *state = &dev->states[0];
- struct cpuidle_state_usage *state_usage = &dev->states_usage[0];
-
- cpuidle_set_statedata(state_usage, NULL);
+ struct cpuidle_state *state = &drv->states[0];
snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
@@ -199,7 +198,7 @@ static void poll_idle_init(struct cpuidle_device *dev)
state->enter = poll_idle;
}
#else
-static void poll_idle_init(struct cpuidle_device *dev) {}
+static void poll_idle_init(struct cpuidle_driver *drv) {}
#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
/**
@@ -226,13 +225,13 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret;
}
- poll_idle_init(dev);
+ poll_idle_init(cpuidle_get_driver());
if ((ret = cpuidle_add_state_sysfs(dev)))
return ret;
if (cpuidle_curr_governor->enable &&
- (ret = cpuidle_curr_governor->enable(dev)))
+ (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
goto fail_sysfs;
for (i = 0; i < dev->state_count; i++) {
@@ -273,7 +272,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
dev->enabled = 0;
if (cpuidle_curr_governor->disable)
- cpuidle_curr_governor->disable(dev);
+ cpuidle_curr_governor->disable(cpuidle_get_driver(), dev);
cpuidle_remove_state_sysfs(dev);
enabled_devices--;
@@ -301,26 +300,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
init_completion(&dev->kobj_unregister);
- /*
- * cpuidle driver should set the dev->power_specified bit
- * before registering the device if the driver provides
- * power_usage numbers.
- *
- * For those devices whose ->power_specified is not set,
- * we fill in power_usage with decreasing values as the
- * cpuidle code has an implicit assumption that state Cn
- * uses less power than C(n-1).
- *
- * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
- * an power value of -1. So we use -2, -3, etc, for other
- * c-states.
- */
- if (!dev->power_specified) {
- int i;
- for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++)
- dev->states[i].power_usage = -1 - i;
- }
-
per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
if ((ret = cpuidle_add_sysfs(sys_dev))) {
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 3f7e3ce..284d7af 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -17,6 +17,30 @@
static struct cpuidle_driver *cpuidle_curr_driver;
DEFINE_SPINLOCK(cpuidle_driver_lock);
+static void __cpuidle_register_driver(struct cpuidle_driver *drv)
+{
+ int i;
+ /*
+ * cpuidle driver should set the drv->power_specified bit
+ * before registering if the driver provides
+ * power_usage numbers.
+ *
+ * If power_specified is not set,
+ * we fill in power_usage with decreasing values as the
+ * cpuidle code has an implicit assumption that state Cn
+ * uses less power than C(n-1).
+ *
+ * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
+ * an power value of -1. So we use -2, -3, etc, for other
+ * c-states.
+ */
+ if (!drv->power_specified) {
+ for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
+ drv->states[i].power_usage = -1 - i;
+ }
+}
+
+
/**
* cpuidle_register_driver - registers a driver
* @drv: the driver
@@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv)
spin_unlock(&cpuidle_driver_lock);
return -EBUSY;
}
+ __cpuidle_register_driver(drv);
cpuidle_curr_driver = drv;
spin_unlock(&cpuidle_driver_lock);
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 78b06d2..261e57a 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev,
/**
* ladder_select_state - selects the next state to enter
+ * @drv: cpuidle driver
* @dev: the CPU
*/
-static int ladder_select_state(struct cpuidle_device *dev)
+static int ladder_select_state(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev)
{
struct ladder_device *ldev = &__get_cpu_var(ladder_devices);
struct ladder_device_state *last_state;
@@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev)
last_state = &ldev->states[last_idx];
- if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID)
- last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency;
+ if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) {
+ last_residency = cpuidle_get_last_residency(dev) - \
+ drv->states[last_idx].exit_latency;
+ }
else
last_residency = last_state->threshold.promotion_time + 1;
/* consider promotion */
- if (last_idx < dev->state_count - 1 &&
+ if (last_idx < drv->state_count - 1 &&
last_residency > last_state->threshold.promotion_time &&
- dev->states[last_idx + 1].exit_latency <= latency_req) {
+ drv->states[last_idx + 1].exit_latency <= latency_req) {
last_state->stats.promotion_count++;
last_state->stats.demotion_count = 0;
if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) {
@@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
/* consider demotion */
if (last_idx > CPUIDLE_DRIVER_STATE_START &&
- dev->states[last_idx].exit_latency > latency_req) {
+ drv->states[last_idx].exit_latency > latency_req) {
int i;
for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
- if (dev->states[i].exit_latency <= latency_req)
+ if (drv->states[i].exit_latency <= latency_req)
break;
}
ladder_do_selection(ldev, last_idx, i);
@@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev)
/**
* ladder_enable_device - setup for the governor
+ * @drv: cpuidle driver
* @dev: the CPU
*/
-static int ladder_enable_device(struct cpuidle_device *dev)
+static int ladder_enable_device(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev)
{
int i;
struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu);
@@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev)
ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START;
- for (i = 0; i < dev->state_count; i++) {
- state = &dev->states[i];
+ for (i = 0; i < drv->state_count; i++) {
+ state = &drv->states[i];
lstate = &ldev->states[i];
lstate->stats.promotion_count = 0;
@@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev)
lstate->threshold.promotion_count = PROMOTION_COUNT;
lstate->threshold.demotion_count = DEMOTION_COUNT;
- if (i < dev->state_count - 1)
+ if (i < drv->state_count - 1)
lstate->threshold.promotion_time = state->exit_latency;
if (i > 0)
lstate->threshold.demotion_time = state->exit_latency;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 31dd287..b2b0c32 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -182,7 +182,7 @@ static inline int performance_multiplier(void)
static DEFINE_PER_CPU(struct menu_device, menu_devices);
-static void menu_update(struct cpuidle_device *dev);
+static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
/* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */
static u64 div_round64(u64 dividend, u32 divisor)
@@ -228,9 +228,10 @@ static void detect_repeating_patterns(struct menu_device *data)
/**
* menu_select - selects the next idle state to enter
+ * @drv: cpuidle driver containing state data
* @dev: the CPU
*/
-static int menu_select(struct cpuidle_device *dev)
+static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
@@ -240,7 +241,7 @@ static int menu_select(struct cpuidle_device *dev)
struct timespec t;
if (data->needs_update) {
- menu_update(dev);
+ menu_update(drv, dev);
data->needs_update = 0;
}
@@ -285,8 +286,8 @@ static int menu_select(struct cpuidle_device *dev)
* Find the idle state with the lowest power while satisfying
* our constraints.
*/
- for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) {
- struct cpuidle_state *s = &dev->states[i];
+ for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
+ struct cpuidle_state *s = &drv->states[i];
if (s->target_residency > data->predicted_us)
continue;
@@ -323,14 +324,15 @@ static void menu_reflect(struct cpuidle_device *dev, int index)
/**
* menu_update - attempts to guess what happened after entry
+ * @drv: cpuidle driver containing state data
* @dev: the CPU
*/
-static void menu_update(struct cpuidle_device *dev)
+static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
{
struct menu_device *data = &__get_cpu_var(menu_devices);
int last_idx = data->last_state_idx;
unsigned int last_idle_us = cpuidle_get_last_residency(dev);
- struct cpuidle_state *target = &dev->states[last_idx];
+ struct cpuidle_state *target = &drv->states[last_idx];
unsigned int measured_us;
u64 new_factor;
@@ -384,9 +386,11 @@ static void menu_update(struct cpuidle_device *dev)
/**
* menu_enable_device - scans a CPU's states and does setup
+ * @drv: cpuidle driver
* @dev: the CPU
*/
-static int menu_enable_device(struct cpuidle_device *dev)
+static int menu_enable_device(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev)
{
struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 8a1ace1..1e756e1 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -322,13 +322,14 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
{
int i, ret = -ENOMEM;
struct cpuidle_state_kobj *kobj;
+ struct cpuidle_driver *drv = cpuidle_get_driver();
/* state statistics */
for (i = 0; i < device->state_count; i++) {
kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
if (!kobj)
goto error_state;
- kobj->state = &device->states[i];
+ kobj->state = &drv->states[i];
kobj->state_usage = &device->states_usage[i];
init_completion(&kobj->kobj_unregister);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 3aa8d4c..5be9d59 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,7 +81,8 @@ static unsigned int mwait_substates;
static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
-static int intel_idle(struct cpuidle_device *dev, int index);
+static int intel_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
static struct cpuidle_state *cpuidle_state_table;
@@ -227,13 +228,15 @@ static int get_driver_data(int cstate)
/**
* intel_idle
* @dev: cpuidle_device
+ * @drv: cpuidle driver
* @index: index of cpuidle state
*
*/
-static int intel_idle(struct cpuidle_device *dev, int index)
+static int intel_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
unsigned long ecx = 1; /* break on interrupt flag */
- struct cpuidle_state *state = &dev->states[index];
+ struct cpuidle_state *state = &drv->states[index];
struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage);
unsigned int cstate;
@@ -420,6 +423,60 @@ static void intel_idle_cpuidle_devices_uninit(void)
return;
}
/*
+ * intel_idle_cpuidle_driver_init()
+ * allocate, initialize cpuidle_states
+ */
+static int intel_idle_cpuidle_driver_init(void)
+{
+ int cstate;
+ struct cpuidle_driver *drv = &intel_idle_driver;
+
+ drv->state_count = 1;
+
+ for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) {
+ int num_substates;
+
+ if (cstate > max_cstate) {
+ printk(PREFIX "max_cstate %d reached\n",
+ max_cstate);
+ break;
+ }
+
+ /* does the state exist in CPUID.MWAIT? */
+ num_substates = (mwait_substates >> ((cstate) * 4))
+ & MWAIT_SUBSTATE_MASK;
+ if (num_substates = 0)
+ continue;
+ /* is the state not enabled? */
+ if (cpuidle_state_table[cstate].enter = NULL) {
+ /* does the driver not know about the state? */
+ if (*cpuidle_state_table[cstate].name = '\0')
+ pr_debug(PREFIX "unaware of model 0x%x"
+ " MWAIT %d please"
+ " contact lenb@kernel.org",
+ boot_cpu_data.x86_model, cstate);
+ continue;
+ }
+
+ if ((cstate > 2) &&
+ !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ mark_tsc_unstable("TSC halts in idle"
+ " states deeper than C2");
+
+ drv->states[drv->state_count] = /* structure copy */
+ cpuidle_state_table[cstate];
+
+ drv->state_count += 1;
+ }
+
+ if (auto_demotion_disable_flags)
+ smp_call_function(auto_demotion_disable, NULL, 1);
+
+ return 0;
+}
+
+
+/*
* intel_idle_cpuidle_devices_init()
* allocate, initialize, register cpuidle_devices
*/
@@ -453,23 +510,9 @@ static int intel_idle_cpuidle_devices_init(void)
continue;
/* is the state not enabled? */
if (cpuidle_state_table[cstate].enter = NULL) {
- /* does the driver not know about the state? */
- if (*cpuidle_state_table[cstate].name = '\0')
- pr_debug(PREFIX "unaware of model 0x%x"
- " MWAIT %d please"
- " contact lenb@kernel.org",
- boot_cpu_data.x86_model, cstate);
continue;
}
- if ((cstate > 2) &&
- !boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
- mark_tsc_unstable("TSC halts in idle"
- " states deeper than C2");
-
- dev->states[dev->state_count] = /* structure copy */
- cpuidle_state_table[cstate];
-
dev->states_usage[dev->state_count].driver_data (void *)get_driver_data(cstate);
@@ -484,8 +527,6 @@ static int intel_idle_cpuidle_devices_init(void)
return -EIO;
}
}
- if (auto_demotion_disable_flags)
- smp_call_function(auto_demotion_disable, NULL, 1);
return 0;
}
@@ -503,6 +544,7 @@ static int __init intel_idle_init(void)
if (retval)
return retval;
+ intel_idle_cpuidle_driver_init();
retval = cpuidle_register_driver(&intel_idle_driver);
if (retval) {
printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 67055f1..610f6fb 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -329,6 +329,7 @@ extern void acpi_processor_throttling_init(void);
int acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device);
int acpi_processor_cst_has_changed(struct acpi_processor *pr);
+int acpi_processor_hotplug(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device);
int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 0156540..c904188 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -22,6 +22,7 @@
#define CPUIDLE_DESC_LEN 32
struct cpuidle_device;
+struct cpuidle_driver;
/****************************
@@ -45,6 +46,7 @@ struct cpuidle_state {
unsigned int target_residency; /* in US */
int (*enter) (struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
int index);
};
@@ -83,12 +85,10 @@ struct cpuidle_state_kobj {
struct cpuidle_device {
unsigned int registered:1;
unsigned int enabled:1;
- unsigned int power_specified:1;
unsigned int cpu;
int last_residency;
int state_count;
- struct cpuidle_state states[CPUIDLE_STATE_MAX];
struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
@@ -96,7 +96,6 @@ struct cpuidle_device {
struct kobject kobj;
struct completion kobj_unregister;
void *governor_data;
- int safe_state_index;
};
DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
@@ -120,6 +119,11 @@ static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
struct cpuidle_driver {
char name[CPUIDLE_NAME_LEN];
struct module *owner;
+
+ unsigned int power_specified:1;
+ struct cpuidle_state states[CPUIDLE_STATE_MAX];
+ int state_count;
+ int safe_state_index;
};
#ifdef CONFIG_CPU_IDLE
@@ -166,10 +170,13 @@ struct cpuidle_governor {
struct list_head governor_list;
unsigned int rating;
- int (*enable) (struct cpuidle_device *dev);
- void (*disable) (struct cpuidle_device *dev);
+ int (*enable) (struct cpuidle_driver *drv,
+ struct cpuidle_device *dev);
+ void (*disable) (struct cpuidle_driver *drv,
+ struct cpuidle_device *dev);
- int (*select) (struct cpuidle_device *dev);
+ int (*select) (struct cpuidle_driver *drv,
+ struct cpuidle_device *dev);
void (*reflect) (struct cpuidle_device *dev, int index);
struct module *owner;
^ permalink raw reply related
* Re: Question about clk->usecount
From: Kuninori Morimoto @ 2011-10-28 10:53 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <87fwihj3x8.wl%kuninori.morimoto.gx@renesas.com>
Hi Paul
Cc Magnus, Rafael
Thank you for your reply
> > Does hwblk/pm_runtime (?) not care clk->usecount ?
>
> I suspect this is a result of hwblk bitrot with regards to the rest of
> the runtime PM changes. We can of course simply inhibit the late clock
> disabling, but the proper solution would be to fix up (or simply kill
> off) the hwblk bits completely.
>
> We can also just add a kernel command line option for inhibiting the late
> disable for testing/development cases, but this is not something we'd
> want to rely on in general.
I investigated hwblk, and I noticed that arch/sh pm_runtime seems
enable/disable hwblk by direct access (out of clk framework).
I guess this is the reason why clk->usecount is 0.
Below is very x10 rough patch which try to use clk framework on hwblk/pm_runtime.
But DON'T believe it, because I'm not good at hwblk/pm_runtime you know.
it seems rescue sh_eth on Ecovec board for me.
But NOT be well tested ;P
Magnus, Rafael
Does this patch become hint to fix this issue ?
---
arch/sh/include/asm/hwblk.h | 5 ++-
arch/sh/kernel/cpu/hwblk.c | 18 ++++++++++++--
arch/sh/kernel/cpu/shmobile/pm_runtime.c | 36 ++++++++++++++++++++++++-----
3 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/arch/sh/include/asm/hwblk.h b/arch/sh/include/asm/hwblk.h
index 855e945..85515ef 100644
--- a/arch/sh/include/asm/hwblk.h
+++ b/arch/sh/include/asm/hwblk.h
@@ -1,6 +1,7 @@
#ifndef __ASM_SH_HWBLK_H
#define __ASM_SH_HWBLK_H
+#include <linux/clk.h>
#include <asm/clock.h>
#include <asm/io.h>
@@ -35,6 +36,7 @@ struct hwblk {
unsigned char bit;
unsigned char area;
int cnt[HWBLK_CNT_NR];
+ struct clk *clk;
};
struct hwblk_info {
@@ -51,8 +53,7 @@ int arch_hwblk_sleep_mode(void);
int hwblk_register(struct hwblk_info *info);
int hwblk_init(void);
-void hwblk_enable(struct hwblk_info *info, int hwblk);
-void hwblk_disable(struct hwblk_info *info, int hwblk);
+struct clk* hwblk_get_clk(struct hwblk_info *info, int hwblk);
void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int cnt);
void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int cnt);
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c
index 3e985aa..b982bad 100644
--- a/arch/sh/kernel/cpu/hwblk.c
+++ b/arch/sh/kernel/cpu/hwblk.c
@@ -55,7 +55,14 @@ void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter)
hwblk_mod_cnt(info, hwblk, counter, -1, 0);
}
-void hwblk_enable(struct hwblk_info *info, int hwblk)
+struct clk* hwblk_get_clk(struct hwblk_info *info, int hwblk)
+{
+ struct hwblk *hp = info->hwblks + hwblk;
+
+ return hp->clk;
+}
+
+static void hwblk_enable(struct hwblk_info *info, int hwblk)
{
struct hwblk *hp = info->hwblks + hwblk;
unsigned long tmp;
@@ -74,7 +81,7 @@ void hwblk_enable(struct hwblk_info *info, int hwblk)
spin_unlock_irqrestore(&hwblk_lock, flags);
}
-void hwblk_disable(struct hwblk_info *info, int hwblk)
+static void hwblk_disable(struct hwblk_info *info, int hwblk)
{
struct hwblk *hp = info->hwblks + hwblk;
unsigned long tmp;
@@ -152,7 +159,12 @@ int __init sh_hwblk_clk_register(struct clk *clks, int nr)
continue;
clkp->ops = &sh_hwblk_clk_ops;
- ret |= clk_register(clkp);
+ ret = clk_register(clkp);
+ if (ret < 0)
+ return ret;
+
+ if (hwblk_info)
+ hwblk_info->hwblks[k].clk = clkp;
}
return ret;
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
index bf280c8..aa20456 100644
--- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c
+++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
@@ -40,13 +40,18 @@ static int __platform_pm_runtime_resume(struct platform_device *pdev)
{
struct device *d = &pdev->dev;
struct pdev_archdata *ad = &pdev->archdata;
+ struct clk *clk;
int hwblk = ad->hwblk_id;
int ret = -ENOSYS;
dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk);
+ clk = hwblk_get_clk(hwblk_info, hwblk);
+ if (!clk)
+ return -EIO;
+
if (d->driver) {
- hwblk_enable(hwblk_info, hwblk);
+ clk_enable(clk);
ret = 0;
if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) {
@@ -56,7 +61,7 @@ static int __platform_pm_runtime_resume(struct platform_device *pdev)
if (!ret)
clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags);
else
- hwblk_disable(hwblk_info, hwblk);
+ clk_disable(clk);
}
}
@@ -70,9 +75,14 @@ static int __platform_pm_runtime_suspend(struct platform_device *pdev)
{
struct device *d = &pdev->dev;
struct pdev_archdata *ad = &pdev->archdata;
+ struct clk *clk;
int hwblk = ad->hwblk_id;
int ret = -ENOSYS;
+ clk = hwblk_get_clk(hwblk_info, hwblk);
+ if (!clk)
+ return -EIO;
+
dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk);
if (d->driver) {
@@ -80,9 +90,9 @@ static int __platform_pm_runtime_suspend(struct platform_device *pdev)
ret = 0;
if (d->driver->pm && d->driver->pm->runtime_suspend) {
- hwblk_enable(hwblk_info, hwblk);
+ clk_enable(clk);
ret = d->driver->pm->runtime_suspend(d);
- hwblk_disable(hwblk_info, hwblk);
+ clk_disable(clk);
}
if (!ret) {
@@ -143,6 +153,7 @@ static int default_platform_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pdev_archdata *ad = &pdev->archdata;
+ struct clk *clk;
unsigned long flags;
int hwblk = ad->hwblk_id;
int ret = 0;
@@ -153,6 +164,12 @@ static int default_platform_runtime_suspend(struct device *dev)
if (!hwblk)
goto out;
+ clk = hwblk_get_clk(hwblk_info, hwblk);
+ if (!clk) {
+ ret = -EIO;
+ goto out;
+ }
+
/* interrupt context not allowed */
might_sleep();
@@ -166,7 +183,7 @@ static int default_platform_runtime_suspend(struct device *dev)
mutex_lock(&ad->mutex);
/* disable clock */
- hwblk_disable(hwblk_info, hwblk);
+ clk_disable(clk);
/* put device on idle list */
spin_lock_irqsave(&hwblk_lock, flags);
@@ -271,18 +288,23 @@ static int platform_bus_notify(struct notifier_block *nb,
struct device *dev = data;
struct platform_device *pdev = to_platform_device(dev);
int hwblk = pdev->archdata.hwblk_id;
+ struct clk *clk;
/* ignore off-chip platform devices */
if (!hwblk)
return 0;
+ clk = hwblk_get_clk(hwblk_info, hwblk);
+ if (!clk)
+ return -EIO;
+
switch (action) {
case BUS_NOTIFY_ADD_DEVICE:
INIT_LIST_HEAD(&pdev->archdata.entry);
mutex_init(&pdev->archdata.mutex);
/* platform devices without drivers should be disabled */
- hwblk_enable(hwblk_info, hwblk);
- hwblk_disable(hwblk_info, hwblk);
+ clk_enable(clk);
+ clk_disable(clk);
/* make sure driver re-inits itself once */
__set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
dev->pm_domain = &default_pm_domain;
--
1.7.5.4
^ permalink raw reply related
* Re: [PATCH 16/49] SH: irq: Remove IRQF_DISABLED
From: Paul Mundt @ 2011-10-28 6:17 UTC (permalink / raw)
To: Yong Zhang; +Cc: linux-kernel, tglx, linux-sh
In-Reply-To: <1319277421-9203-17-git-send-email-yong.zhang0@gmail.com>
On Sat, Oct 22, 2011 at 05:56:28PM +0800, Yong Zhang wrote:
> Since commit [e58aa3d2: genirq: Run irq handlers with interrupts disabled],
> We run all interrupt handlers with interrupts disabled
> and we even check and yell when an interrupt handler
> returns with interrupts enabled (see commit [b738a50a:
> genirq: Warn when handler enables interrupts]).
>
> So now this flag is a NOOP and can be removed.
>
> Signed-off-by: Yong Zhang <yong.zhang0@gmail.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH/linux-next] sh: userimask.c needs linux/stat.h
From: Paul Mundt @ 2011-10-28 6:14 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <1317691041-20226-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com>
On Tue, Oct 04, 2011 at 10:17:21AM +0900, Nobuhiro Iwamatsu wrote:
> This fix the problem that S_IRUSR and S_IWUSR are not solved in userimask.c.
>
> -----
> CC drivers/usb/host/r8a66597-hcd.o
> drivers/sh/intc/userimask.c:57: error: ???S_IRUSR??? undeclared here (not in a function)
> drivers/sh/intc/userimask.c:57: error: ???S_IWUSR??? undeclared here (not in a function)
> CC drivers/watchdog/shwdt.o
> -----
>
> Signed-off-by: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] sh: intc: Add IRQ trigger bit field check
From: Paul Mundt @ 2011-10-28 6:13 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <20111017085954.21977.43477.sendpatchset@w520>
On Mon, Oct 17, 2011 at 05:59:54PM +0900, Magnus Damm wrote:
> From: Magnus Damm <damm@opensource.se>
>
> R-Mobile SoCs such as sh73a0 include PINT blocks in INTC
> that come with 2-bit IRQ trigger support. Add code to make
> sure the bit width is checked so 4-bit only modes like for
> instance EDGE_BOTH will fail for PINT.
>
> Signed-off-by: Magnus Damm <damm@opensource.se>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 05/21] sh: drop unused Kconfig symbol
From: Paul Mundt @ 2011-10-28 6:11 UTC (permalink / raw)
To: Paul Bolle; +Cc: linux-sh, linux-kernel
In-Reply-To: <1318595280.6132.61.camel@x61.thuisdomein>
On Fri, Oct 14, 2011 at 02:28:00PM +0200, Paul Bolle wrote:
> Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
> ---
> arch/sh/Kconfig | 4 ----
> 1 files changed, 0 insertions(+), 4 deletions(-)
>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] sh: modify the asm/sh_eth.h to linux/sh_eth.h in some boards
From: Paul Mundt @ 2011-10-28 6:09 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <4E82D17A.7050108@renesas.com>
On Wed, Sep 28, 2011 at 04:49:14PM +0900, Yoshihiro Shimoda wrote:
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
> - This patch depends on the following patch:
> - net: sh_eth: move the asm/sh_eth.h to include/linux/
> - This patch doesn't contain board-sh7757lcr.c, because
> it needs more modification.
>
> arch/sh/boards/board-espt.c | 2 +-
> arch/sh/boards/mach-ecovec24/setup.c | 2 +-
> arch/sh/boards/mach-se/7724/setup.c | 2 +-
> arch/sh/boards/mach-sh7763rdp/setup.c | 2 +-
> 4 files changed, 4 insertions(+), 4 deletions(-)
>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] sh: add parameters for EHCI and RIIC in clock-sh7757.c
From: Paul Mundt @ 2011-10-28 6:07 UTC (permalink / raw)
To: linux-sh
On Mon, Sep 26, 2011 at 05:41:28PM +0900, Yoshihiro Shimoda wrote:
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> ---
> arch/sh/kernel/cpu/sh4a/clock-sh7757.c | 10 +++++++++-
> 1 files changed, 9 insertions(+), 1 deletions(-)
Applied, thanks.
^ permalink raw reply
* Re: [PATCH] sh: pfc: Remove unused gpio_in_use member
From: Paul Mundt @ 2011-10-28 6:06 UTC (permalink / raw)
To: linux-sh
On Wed, Sep 28, 2011 at 04:47:06PM +0900, Magnus Damm wrote:
> Remove unused member gpio_in_use from struct pinmux_info.
>
On Wed, Sep 28, 2011 at 04:50:58PM +0900, Magnus Damm wrote:
> Add GPIO IRQ support to the shared PFC code in drivers/sh/pfc.c
>
> The enums pointed out by a certain GPIO will be matched against
> a table for IRQ to enum mappings.
>
> Only the shared PFC code is updated by this patch. SoC specific
> changes are also needed to allow platforms to make use of this
> feature.
Both applied, thanks.
^ permalink raw reply
* Re: [PATCH] sh: kexec: Add PHYSICAL_START
From: Paul Mundt @ 2011-10-28 6:05 UTC (permalink / raw)
To: linux-sh
On Thu, Sep 15, 2011 at 08:13:00PM +0900, Simon Horman wrote:
> Add PHYSICAL_START kernel configuration parameter to set the address at
> which the kernel should be loaded.
>
> It has been observed on an sh7757lcr that simply modifying MEMORY_START
> does not achieve this goal for 32bit sh. This is due to MEMORY_OFFSET in
> arch/sh/kernel/vmlinux.lds.S bot being based on MEMORY_START on such
> systems.
>
> Signed-off-by: Simon Horman <horms@verge.net.au>
No one seems to have complained about this, so I've applied it.
^ permalink raw reply
* Re: Question about clk->usecount
From: Paul Mundt @ 2011-10-28 5:36 UTC (permalink / raw)
To: linux-sh
In-Reply-To: <87fwihj3x8.wl%kuninori.morimoto.gx@renesas.com>
On Mon, Oct 24, 2011 at 05:44:25PM -0700, kuninori.morimoto.gx@renesas.com wrote:
> renesas_usbhs and sh_eth seems break in SH7724 ecovec board
> from 794d78fea51504bad3880d14f354a9847f318f25 (drivers: sh: late disabling of clocks V2)
> So I debuged it.
>
> when these driver call pm_runtime_get_sync(),
> then, arch/sh/kernel/cpu/hwblk.c :: hwblk_enable() are called,
> and it enabled MSTP bit.
> This is OK.
>
> But clk_late_init() disabled it.
>
> Does hwblk/pm_runtime (?) not care clk->usecount ?
I suspect this is a result of hwblk bitrot with regards to the rest of
the runtime PM changes. We can of course simply inhibit the late clock
disabling, but the proper solution would be to fix up (or simply kill
off) the hwblk bits completely.
We can also just add a kernel command line option for inhibiting the late
disable for testing/development cases, but this is not something we'd
want to rely on in general.
^ permalink raw reply
* [PATCH v2] asm-generic/gpio.h: merge basic gpiolib wrappers
From: Mike Frysinger @ 2011-10-27 22:52 UTC (permalink / raw)
To: Grant Likely, Richard Henderson, Ivan Kokshaysky, Matt Turner,
Haavard Skinnemoen <hskin>
Cc: linux-alpha, linux-arch, linux-ia64, microblaze-uclinux,
linux-mips, linux-sh, linux, linuxppc-dev, sparclinux, x86,
linux-arm-kernel, uclinux-dist-devel, linux-kernel,
Mike Frysinger, linux-m68k
In-Reply-To: <1319720503-3183-1-git-send-email-vapier@gentoo.org>
Rather than requiring architectures that use gpiolib but don't have
any need to define anything custom to copy an asm/gpio.h, merge this
code into the asm-generic/gpio.h. We add ifdef checks so that arches
can still override things while using the asm-generic/gpio.h, but on
a more fine grained per-func approach.
I've compile tested these guys (with & without GPIOLIB), but don't
have the hardware to boot:
- alpha defconfig
- arm: every defconfig
- blackfin defconfig
- ia64 defconfig
- m68k: multi & m5208evb defconfig
- mips: ar7 & ath79 & bcm47xx & bcm63xx & ip22 defconfig
- powerpc: mpc85xx & ppc64 defconfig
- sh: kfr2r09 defconfig
- sparc defconfig
- x86_64 defconfig
There is concern for adding code to the arm gpio headers, but since my
diffstat removes more than it adds, and it only adds when there are funcs
which need to be customized in the first place, I think this holds to the
desire to ultimately kill off (when possible) the misc sub gpio headers.
After all, if you can kill the overridden function, my additional lines
shouldn't be needed either.
I don't have any toolchains for avr32, microblaze, openrisc, unicore32,
or xtensa. So they lose :x.
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
---
v2
- grub through arm gpio.h headers
- add m68k support
note: i've done a full build of all arm defconfigs, and any warnings
or build failures appear to be unrelated to my change (sadly, there
seem to be way more than there should be ...). i'll start a 2nd
build which compares the binary output to make sure they're the
same, but if people see something that needs more attention before
that, feel free to highlight it.
arch/alpha/include/asm/Kbuild | 2 +
arch/alpha/include/asm/gpio.h | 55 -------------------
arch/arm/include/asm/gpio.h | 16 ------
arch/arm/include/asm/hardware/iop3xx-gpio.h | 21 ++------
arch/arm/mach-davinci/include/mach/gpio.h | 11 ++--
arch/arm/mach-ixp4xx/include/mach/gpio.h | 8 +--
arch/arm/mach-ks8695/include/mach/gpio.h | 1 +
arch/arm/mach-mmp/include/mach/gpio.h | 2 -
arch/arm/mach-pxa/include/mach/gpio.h | 2 +-
arch/arm/mach-sa1100/include/mach/gpio.h | 13 ++---
arch/arm/mach-shmobile/include/mach/gpio.h | 16 ------
arch/arm/mach-w90x900/include/mach/gpio.h | 1 +
arch/arm/plat-mxc/include/mach/irqs.h | 2 -
arch/arm/plat-omap/include/plat/gpio.h | 4 +-
arch/arm/plat-pxa/include/plat/gpio.h | 6 +--
arch/avr32/mach-at32ap/include/mach/gpio.h | 19 +------
arch/blackfin/include/asm/gpio.h | 16 ++----
arch/ia64/include/asm/Kbuild | 2 +
arch/ia64/include/asm/gpio.h | 55 -------------------
arch/m68k/include/asm/gpio.h | 7 +++
arch/microblaze/include/asm/Kbuild | 2 +
arch/microblaze/include/asm/gpio.h | 53 ------------------
arch/mips/include/asm/mach-ar7/gpio.h | 5 --
arch/mips/include/asm/mach-ath79/gpio.h | 8 ++-
arch/mips/include/asm/mach-bcm47xx/gpio.h | 3 +
arch/mips/include/asm/mach-bcm63xx/gpio.h | 5 --
arch/mips/include/asm/mach-generic/gpio.h | 8 +--
arch/mips/include/asm/mach-loongson/gpio.h | 7 +--
arch/mips/include/asm/mach-rc32434/gpio.h | 10 +---
arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h | 12 +---
arch/openrisc/include/asm/Kbuild | 1 +
arch/openrisc/include/asm/gpio.h | 65 -----------------------
arch/powerpc/include/asm/Kbuild | 2 +
arch/powerpc/include/asm/gpio.h | 53 ------------------
arch/sh/include/asm/gpio.h | 32 +-----------
arch/sparc/include/asm/Kbuild | 1 +
arch/sparc/include/asm/gpio.h | 36 -------------
arch/unicore32/include/asm/gpio.h | 8 ++-
arch/x86/include/asm/Kbuild | 2 +
arch/x86/include/asm/gpio.h | 53 ------------------
arch/xtensa/include/asm/Kbuild | 2 +
arch/xtensa/include/asm/gpio.h | 56 -------------------
include/asm-generic/gpio.h | 23 ++++++++
43 files changed, 105 insertions(+), 601 deletions(-)
delete mode 100644 arch/alpha/include/asm/gpio.h
delete mode 100644 arch/ia64/include/asm/gpio.h
delete mode 100644 arch/microblaze/include/asm/gpio.h
delete mode 100644 arch/openrisc/include/asm/gpio.h
delete mode 100644 arch/powerpc/include/asm/gpio.h
delete mode 100644 arch/sparc/include/asm/gpio.h
delete mode 100644 arch/x86/include/asm/gpio.h
delete mode 100644 arch/xtensa/include/asm/gpio.h
diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild
index e423def..0bcff1a 100644
--- a/arch/alpha/include/asm/Kbuild
+++ b/arch/alpha/include/asm/Kbuild
@@ -1,5 +1,7 @@
include include/asm-generic/Kbuild.asm
+generic-y += gpio.h
+
header-y += compiler.h
header-y += console.h
header-y += fpu.h
diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h
deleted file mode 100644
index 7dc6a63..0000000
--- a/arch/alpha/include/asm/gpio.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Generic GPIO API implementation for Alpha.
- *
- * A stright copy of that for PowerPC which was:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_ALPHA_GPIO_H
-#define _ASM_ALPHA_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_ALPHA_GPIO_H */
diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h
index 11ad0bf..9818329 100644
--- a/arch/arm/include/asm/gpio.h
+++ b/arch/arm/include/asm/gpio.h
@@ -4,23 +4,7 @@
/* not all ARM platforms necessarily support this API ... */
#include <mach/gpio.h>
-#ifndef __ARM_GPIOLIB_COMPLEX
/* Note: this may rely upon the value of ARCH_NR_GPIOS set in mach/gpio.h */
#include <asm-generic/gpio.h>
-/* The trivial gpiolib dispatchers */
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep __gpio_cansleep
-#endif
-
-/*
- * Provide a default gpio_to_irq() which should satisfy every case.
- * However, some platforms want to do this differently, so allow them
- * to override it.
- */
-#ifndef gpio_to_irq
-#define gpio_to_irq __gpio_to_irq
-#endif
-
#endif /* _ARCH_ARM_GPIO_H */
diff --git a/arch/arm/include/asm/hardware/iop3xx-gpio.h b/arch/arm/include/asm/hardware/iop3xx-gpio.h
index 9eda7dc..4033b81 100644
--- a/arch/arm/include/asm/hardware/iop3xx-gpio.h
+++ b/arch/arm/include/asm/hardware/iop3xx-gpio.h
@@ -25,11 +25,14 @@
#ifndef __ASM_ARM_HARDWARE_IOP3XX_GPIO_H
#define __ASM_ARM_HARDWARE_IOP3XX_GPIO_H
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define gpio_cansleep gpio_cansleep
+
#include <mach/hardware.h>
#include <asm-generic/gpio.h>
-#define __ARM_GPIOLIB_COMPLEX
-
#define IOP3XX_N_GPIOS 8
static inline int gpio_get_value(unsigned gpio)
@@ -57,19 +60,5 @@ static inline int gpio_cansleep(unsigned gpio)
return __gpio_cansleep(gpio);
}
-/*
- * The GPIOs are not generating any interrupt
- * Note : manuals are not clear about this
- */
-static inline int gpio_to_irq(int gpio)
-{
- return -EINVAL;
-}
-
-static inline int irq_to_gpio(int gpio)
-{
- return -EINVAL;
-}
-
#endif
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index fbaae47..1604005 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -13,6 +13,11 @@
#ifndef __DAVINCI_GPIO_H
#define __DAVINCI_GPIO_H
+/* We implement a few ourself */
+#define gpio_set_value gpio_set_value
+#define gpio_get_value gpio_get_value
+#define gpio_cansleep gpio_cansleep
+
#include <asm-generic/gpio.h>
/* The inline versions use the static inlines in the driver header */
@@ -77,10 +82,4 @@ static inline int gpio_cansleep(unsigned gpio)
return __gpio_cansleep(gpio);
}
-static inline int irq_to_gpio(unsigned irq)
-{
- /* don't support the reverse mapping */
- return -ENOSYS;
-}
-
#endif /* __DAVINCI_GPIO_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/gpio.h b/arch/arm/mach-ixp4xx/include/mach/gpio.h
index 83d6b4e..7835e31 100644
--- a/arch/arm/mach-ixp4xx/include/mach/gpio.h
+++ b/arch/arm/mach-ixp4xx/include/mach/gpio.h
@@ -28,8 +28,6 @@
#include <linux/kernel.h>
#include <mach/hardware.h>
-#define __ARM_GPIOLIB_COMPLEX
-
static inline int gpio_request(unsigned gpio, const char *label)
{
return 0;
@@ -63,17 +61,17 @@ static inline int gpio_get_value(unsigned gpio)
return value;
}
+#define gpio_get_value gpio_get_value
static inline void gpio_set_value(unsigned gpio, int value)
{
gpio_line_set(gpio, value);
}
-
-#include <asm-generic/gpio.h> /* cansleep wrappers */
+#define gpio_set_value gpio_set_value
extern int gpio_to_irq(int gpio);
#define gpio_to_irq gpio_to_irq
extern int irq_to_gpio(unsigned int irq);
+#define irq_to_gpio irq_to_gpio
#endif
-
diff --git a/arch/arm/mach-ks8695/include/mach/gpio.h b/arch/arm/mach-ks8695/include/mach/gpio.h
index f5fda36..d81c6f8 100644
--- a/arch/arm/mach-ks8695/include/mach/gpio.h
+++ b/arch/arm/mach-ks8695/include/mach/gpio.h
@@ -15,5 +15,6 @@
* Map IRQ number to GPIO line.
*/
extern int irq_to_gpio(unsigned int irq);
+#define irq_to_gpio irq_to_gpio
#endif
diff --git a/arch/arm/mach-mmp/include/mach/gpio.h b/arch/arm/mach-mmp/include/mach/gpio.h
index 6812623..871b4c8 100644
--- a/arch/arm/mach-mmp/include/mach/gpio.h
+++ b/arch/arm/mach-mmp/include/mach/gpio.h
@@ -1,8 +1,6 @@
#ifndef __ASM_MACH_GPIO_H
#define __ASM_MACH_GPIO_H
-#include <asm-generic/gpio.h>
-
#define gpio_to_irq(gpio) (IRQ_GPIO_START + (gpio))
#define irq_to_gpio(irq) ((irq) - IRQ_GPIO_START)
diff --git a/arch/arm/mach-pxa/include/mach/gpio.h b/arch/arm/mach-pxa/include/mach/gpio.h
index 004cade..a28277c 100644
--- a/arch/arm/mach-pxa/include/mach/gpio.h
+++ b/arch/arm/mach-pxa/include/mach/gpio.h
@@ -24,7 +24,6 @@
#ifndef __ASM_ARCH_PXA_GPIO_H
#define __ASM_ARCH_PXA_GPIO_H
-#include <asm-generic/gpio.h>
/* The defines for the driver are needed for the accelerated accessors */
#include "gpio-pxa.h"
@@ -43,6 +42,7 @@ static inline int irq_to_gpio(unsigned int irq)
return -1;
}
+#define irq_to_gpio irq_to_gpio
#include <plat/gpio.h>
#endif
diff --git a/arch/arm/mach-sa1100/include/mach/gpio.h b/arch/arm/mach-sa1100/include/mach/gpio.h
index 7036318..6198f7a 100644
--- a/arch/arm/mach-sa1100/include/mach/gpio.h
+++ b/arch/arm/mach-sa1100/include/mach/gpio.h
@@ -24,12 +24,16 @@
#ifndef __ASM_ARCH_SA1100_GPIO_H
#define __ASM_ARCH_SA1100_GPIO_H
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define gpio_to_irq(gpio) ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \
+ (IRQ_GPIO11 - 11 + gpio))
+
#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm-generic/gpio.h>
-#define __ARM_GPIOLIB_COMPLEX
-
static inline int gpio_get_value(unsigned gpio)
{
if (__builtin_constant_p(gpio) && (gpio <= GPIO_MAX))
@@ -49,9 +53,4 @@ static inline void gpio_set_value(unsigned gpio, int value)
__gpio_set_value(gpio, value);
}
-#define gpio_cansleep __gpio_cansleep
-
-#define gpio_to_irq(gpio) ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \
- (IRQ_GPIO11 - 11 + gpio))
-
#endif
diff --git a/arch/arm/mach-shmobile/include/mach/gpio.h b/arch/arm/mach-shmobile/include/mach/gpio.h
index 7bf0890..f8a5637 100644
--- a/arch/arm/mach-shmobile/include/mach/gpio.h
+++ b/arch/arm/mach-shmobile/include/mach/gpio.h
@@ -10,23 +10,7 @@
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
-#include <linux/kernel.h>
-#include <linux/errno.h>
-
#define ARCH_NR_GPIOS 1024
#include <linux/sh_pfc.h>
-#ifdef CONFIG_GPIOLIB
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -ENOSYS;
-}
-
-#else
-
-#define __ARM_GPIOLIB_COMPLEX
-
-#endif /* CONFIG_GPIOLIB */
-
#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-w90x900/include/mach/gpio.h b/arch/arm/mach-w90x900/include/mach/gpio.h
index 5385a42..c905219 100644
--- a/arch/arm/mach-w90x900/include/mach/gpio.h
+++ b/arch/arm/mach-w90x900/include/mach/gpio.h
@@ -26,5 +26,6 @@ static inline int irq_to_gpio(unsigned irq)
{
return irq;
}
+#define irq_to_gpio irq_to_gpio
#endif
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h
index 00e812b..4589307 100644
--- a/arch/arm/plat-mxc/include/mach/irqs.h
+++ b/arch/arm/plat-mxc/include/mach/irqs.h
@@ -11,8 +11,6 @@
#ifndef __ASM_ARCH_MXC_IRQS_H__
#define __ASM_ARCH_MXC_IRQS_H__
-#include <asm-generic/gpio.h>
-
/*
* SoCs with TZIC interrupt controller have 128 IRQs, those with AVIC have 64
*/
diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 9e86ee0..1fd4986 100644
--- a/arch/arm/plat-omap/include/plat/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
@@ -219,9 +219,6 @@ extern void omap_gpio_restore_context(void);
* The original OMAP-specific calls should eventually be removed.
*/
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
static inline int irq_to_gpio(unsigned irq)
{
int tmp;
@@ -238,5 +235,6 @@ static inline int irq_to_gpio(unsigned irq)
/* we don't supply reverse mappings for non-SOC gpios */
return -EIO;
}
+#define irq_to_gpio irq_to_gpio
#endif
diff --git a/arch/arm/plat-pxa/include/plat/gpio.h b/arch/arm/plat-pxa/include/plat/gpio.h
index 258f772..4ee329c 100644
--- a/arch/arm/plat-pxa/include/plat/gpio.h
+++ b/arch/arm/plat-pxa/include/plat/gpio.h
@@ -1,8 +1,6 @@
#ifndef __PLAT_GPIO_H
#define __PLAT_GPIO_H
-#define __ARM_GPIOLIB_COMPLEX
-
/* The individual machine provides register offsets and NR_BUILTIN_GPIO */
#include <mach/gpio-pxa.h>
@@ -13,6 +11,7 @@ static inline int gpio_get_value(unsigned gpio)
else
return __gpio_get_value(gpio);
}
+#define gpio_get_value gpio_get_value
static inline void gpio_set_value(unsigned gpio, int value)
{
@@ -24,7 +23,6 @@ static inline void gpio_set_value(unsigned gpio, int value)
} else
__gpio_set_value(gpio, value);
}
-
-#define gpio_cansleep __gpio_cansleep
+#define gpio_set_value gpio_set_value
#endif /* __PLAT_GPIO_H */
diff --git a/arch/avr32/mach-at32ap/include/mach/gpio.h b/arch/avr32/mach-at32ap/include/mach/gpio.h
index 0180f58..f2ff962 100644
--- a/arch/avr32/mach-at32ap/include/mach/gpio.h
+++ b/arch/avr32/mach-at32ap/include/mach/gpio.h
@@ -10,26 +10,13 @@
*/
#define ARCH_NR_GPIOS (NR_GPIO_IRQS + 2 * 32)
+/* We implement a few ourself */
+#define gpio_to_irq gpio_to_irq
+#define irq_to_gpio irq_to_gpio
/* Arch-neutral GPIO API, supporting both "native" and external GPIOs. */
#include <asm-generic/gpio.h>
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-
static inline int gpio_to_irq(unsigned int gpio)
{
if (gpio < NR_GPIO_IRQS)
diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
index 5a25856..6e25dcc 100644
--- a/arch/blackfin/include/asm/gpio.h
+++ b/arch/blackfin/include/asm/gpio.h
@@ -189,6 +189,12 @@ void bfin_gpio_set_value(unsigned gpio, int value);
#include <asm/errno.h>
#ifdef CONFIG_GPIOLIB
+
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define irq_to_gpio irq_to_gpio
+
#include <asm-generic/gpio.h> /* cansleep wrappers */
static inline int gpio_get_value(unsigned int gpio)
@@ -207,16 +213,6 @@ static inline void gpio_set_value(unsigned int gpio, int value)
__gpio_set_value(gpio, value);
}
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
#else /* !CONFIG_GPIOLIB */
static inline int gpio_request(unsigned gpio, const char *label)
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 241d1c5..d0fdd2d 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -1,5 +1,7 @@
include include/asm-generic/Kbuild.asm
+generic-y += gpio.h
+
header-y += break.h
header-y += fpu.h
header-y += gcc_intrin.h
diff --git a/arch/ia64/include/asm/gpio.h b/arch/ia64/include/asm/gpio.h
deleted file mode 100644
index 590a20d..0000000
--- a/arch/ia64/include/asm/gpio.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Generic GPIO API implementation for IA-64.
- *
- * A stright copy of that for PowerPC which was:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_IA64_GPIO_H
-#define _ASM_IA64_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_IA64_GPIO_H */
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index b204683..4544b6a 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -16,6 +16,13 @@
#ifndef coldfire_gpio_h
#define coldfire_gpio_h
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define gpio_cansleep gpio_cansleep
+#define gpio_to_irq gpio_to_irq
+#define irq_to_gpio irq_to_gpio
+
#include <linux/io.h>
#include <asm-generic/gpio.h>
#include <asm/coldfire.h>
diff --git a/arch/microblaze/include/asm/Kbuild b/arch/microblaze/include/asm/Kbuild
index db5294c..5bf1ca7 100644
--- a/arch/microblaze/include/asm/Kbuild
+++ b/arch/microblaze/include/asm/Kbuild
@@ -1,3 +1,5 @@
include include/asm-generic/Kbuild.asm
+generic-y += gpio.h
+
header-y += elf.h
diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h
deleted file mode 100644
index 2b2c18b..0000000
--- a/arch/microblaze/include/asm/gpio.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Generic GPIO API implementation for PowerPC.
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_MICROBLAZE_GPIO_H
-#define _ASM_MICROBLAZE_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_MICROBLAZE_GPIO_H */
diff --git a/arch/mips/include/asm/mach-ar7/gpio.h b/arch/mips/include/asm/mach-ar7/gpio.h
index c177cd1..78f40c2 100644
--- a/arch/mips/include/asm/mach-ar7/gpio.h
+++ b/arch/mips/include/asm/mach-ar7/gpio.h
@@ -27,11 +27,6 @@
#define gpio_to_irq(gpio) -1
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-
-#define gpio_cansleep __gpio_cansleep
-
/* Board specific GPIO functions */
int ar7_gpio_enable(unsigned gpio);
int ar7_gpio_disable(unsigned gpio);
diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h
index 60dcb62..2c570a0 100644
--- a/arch/mips/include/asm/mach-ath79/gpio.h
+++ b/arch/mips/include/asm/mach-ath79/gpio.h
@@ -13,6 +13,12 @@
#ifndef __ASM_MACH_ATH79_GPIO_H
#define __ASM_MACH_ATH79_GPIO_H
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define gpio_to_irq gpio_to_irq
+#define irq_to_gpio irq_to_gpio
+
#define ARCH_NR_GPIOS 64
#include <asm-generic/gpio.h>
@@ -21,6 +27,4 @@ int irq_to_gpio(unsigned irq);
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
-#define gpio_cansleep __gpio_cansleep
-
#endif /* __ASM_MACH_ATH79_GPIO_H */
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index 76961ca..d678316 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -19,6 +19,7 @@
extern int gpio_request(unsigned gpio, const char *label);
extern void gpio_free(unsigned gpio);
extern int gpio_to_irq(unsigned gpio);
+#define gpio_to_irq gpio_to_irq
static inline int gpio_get_value(unsigned gpio)
{
@@ -35,6 +36,7 @@ static inline int gpio_get_value(unsigned gpio)
}
return -EINVAL;
}
+#define gpio_get_value gpio_get_value
static inline void gpio_set_value(unsigned gpio, int value)
{
@@ -53,6 +55,7 @@ static inline void gpio_set_value(unsigned gpio, int value)
#endif
}
}
+#define gpio_set_value gpio_set_value
static inline int gpio_direction_input(unsigned gpio)
{
diff --git a/arch/mips/include/asm/mach-bcm63xx/gpio.h b/arch/mips/include/asm/mach-bcm63xx/gpio.h
index 1eb534d..c71bf66 100644
--- a/arch/mips/include/asm/mach-bcm63xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm63xx/gpio.h
@@ -5,11 +5,6 @@
#define gpio_to_irq(gpio) -1
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-
-#define gpio_cansleep __gpio_cansleep
-
#include <asm-generic/gpio.h>
#endif /* __ASM_MIPS_MACH_BCM63XX_GPIO_H */
diff --git a/arch/mips/include/asm/mach-generic/gpio.h b/arch/mips/include/asm/mach-generic/gpio.h
index b4e7020..e8a89c5 100644
--- a/arch/mips/include/asm/mach-generic/gpio.h
+++ b/arch/mips/include/asm/mach-generic/gpio.h
@@ -1,11 +1,7 @@
#ifndef __ASM_MACH_GENERIC_GPIO_H
#define __ASM_MACH_GENERIC_GPIO_H
-#ifdef CONFIG_GPIOLIB
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep __gpio_cansleep
-#else
+#ifndef CONFIG_GPIOLIB
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
@@ -14,7 +10,9 @@ int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
#endif
int gpio_to_irq(unsigned gpio);
+#define gpio_to_irq gpio_to_irq
int irq_to_gpio(unsigned irq);
+#define irq_to_gpio irq_to_gpio
#include <asm-generic/gpio.h> /* cansleep wrappers */
diff --git a/arch/mips/include/asm/mach-loongson/gpio.h b/arch/mips/include/asm/mach-loongson/gpio.h
index e30e73d..df6efc0 100644
--- a/arch/mips/include/asm/mach-loongson/gpio.h
+++ b/arch/mips/include/asm/mach-loongson/gpio.h
@@ -13,6 +13,8 @@
#ifndef __STLS2F_GPIO_H
#define __STLS2F_GPIO_H
+#define gpio_to_irq gpio_to_irq
+
#include <asm-generic/gpio.h>
extern void gpio_set_value(unsigned gpio, int value);
@@ -27,9 +29,4 @@ static inline int gpio_to_irq(int gpio)
return -EINVAL;
}
-static inline int irq_to_gpio(int gpio)
-{
- return -EINVAL;
-}
-
#endif /* __STLS2F_GPIO_H */
diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/asm/mach-rc32434/gpio.h
index 12ee8d5..8b0815b 100644
--- a/arch/mips/include/asm/mach-rc32434/gpio.h
+++ b/arch/mips/include/asm/mach-rc32434/gpio.h
@@ -13,18 +13,14 @@
#ifndef _RC32434_GPIO_H_
#define _RC32434_GPIO_H_
+#define gpio_to_irq(gpio) (8 + 4 * 32 + gpio)
+#define irq_to_gpio(irq) (irq - (8 + 4 * 32))
+
#include <linux/types.h>
#include <asm-generic/gpio.h>
#define NR_BUILTIN_GPIO 32
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep __gpio_cansleep
-
-#define gpio_to_irq(gpio) (8 + 4 * 32 + gpio)
-#define irq_to_gpio(irq) (irq - (8 + 4 * 32))
-
struct rb532_gpio_reg {
u32 gpiofunc; /* GPIO Function Register
* gpiofunc[x]=0 bit = gpio
diff --git a/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h b/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h
index ebdbab9..8356a8e 100644
--- a/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h
+++ b/arch/mips/include/asm/pmc-sierra/msp71xx/gpio.h
@@ -11,16 +11,15 @@
#ifndef __PMC_MSP71XX_GPIO_H
#define __PMC_MSP71XX_GPIO_H
+/* We implement a few ourself */
+#define gpio_to_irq gpio_to_irq
+
/* Max number of gpio's is 28 on chip plus 3 banks of I2C IO Expanders */
#define ARCH_NR_GPIOS (28 + (3 * 8))
/* new generic GPIO API - see Documentation/gpio.txt */
#include <asm-generic/gpio.h>
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep __gpio_cansleep
-
/* Setup calls for the gpio and gpio extended */
extern void msp71xx_init_gpio(void);
extern void msp71xx_init_gpio_extended(void);
@@ -38,9 +37,4 @@ static inline int gpio_to_irq(unsigned gpio)
return -EINVAL;
}
-static inline int irq_to_gpio(unsigned irq)
-{
- return -EINVAL;
-}
-
#endif /* __PMC_MSP71XX_GPIO_H */
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index 11162e6..03f0823 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -23,6 +23,7 @@ generic-y += fb.h
generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
+generic-y += gpio.h
generic-y += hardirq.h
generic-y += hw_irq.h
generic-y += ioctl.h
diff --git a/arch/openrisc/include/asm/gpio.h b/arch/openrisc/include/asm/gpio.h
deleted file mode 100644
index 0b0d174..0000000
--- a/arch/openrisc/include/asm/gpio.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * OpenRISC Linux
- *
- * Linux architectural port borrowing liberally from similar works of
- * others. All original copyrights apply as per the original source
- * declaration.
- *
- * OpenRISC implementation:
- * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
- * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
- * et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __ASM_OPENRISC_GPIO_H
-#define __ASM_OPENRISC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * OpenRISC (or1k) does not have on-chip GPIO's so there is not really
- * any standardized implementation that makes sense here. If passing
- * through gpiolib becomes a bottleneck then it may make sense, on a
- * case-by-case basis, to implement these inlined/rapid versions.
- *
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-/*
- * Not implemented, yet.
- */
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return -ENOSYS;
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_OPENRISC_GPIO_H */
diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
index d51df17..9cf0632 100644
--- a/arch/powerpc/include/asm/Kbuild
+++ b/arch/powerpc/include/asm/Kbuild
@@ -1,5 +1,7 @@
include include/asm-generic/Kbuild.asm
+generic-y += gpio.h
+
header-y += auxvec.h
header-y += bootx.h
header-y += byteorder.h
diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/gpio.h
deleted file mode 100644
index 38762ed..0000000
--- a/arch/powerpc/include/asm/gpio.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Generic GPIO API implementation for PowerPC.
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __ASM_POWERPC_GPIO_H
-#define __ASM_POWERPC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_POWERPC_GPIO_H */
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h
index 04f53d3..44fee05 100644
--- a/arch/sh/include/asm/gpio.h
+++ b/arch/sh/include/asm/gpio.h
@@ -12,9 +12,6 @@
#ifndef __ASM_SH_GPIO_H
#define __ASM_SH_GPIO_H
-#include <linux/kernel.h>
-#include <linux/errno.h>
-
#if defined(CONFIG_CPU_SH3)
#include <cpu/gpio.h>
#endif
@@ -22,33 +19,6 @@
#define ARCH_NR_GPIOS 512
#include <linux/sh_pfc.h>
-#ifdef CONFIG_GPIOLIB
-
-static inline int gpio_get_value(unsigned gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_GPIOLIB */
+#include <asm-generic/gpio.h>
#endif /* __ASM_SH_GPIO_H */
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 2c2e388..6d27595 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -18,6 +18,7 @@ header-y += utrap.h
header-y += watchdog.h
generic-y += div64.h
+generic-y += gpio.h
generic-y += local64.h
generic-y += irq_regs.h
generic-y += local.h
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
deleted file mode 100644
index a0e3ac0..0000000
--- a/arch/sparc/include/asm/gpio.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __ASM_SPARC_GPIO_H
-#define __ASM_SPARC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return -ENOSYS;
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_SPARC_GPIO_H */
diff --git a/arch/unicore32/include/asm/gpio.h b/arch/unicore32/include/asm/gpio.h
index 2716f14..437f4e8 100644
--- a/arch/unicore32/include/asm/gpio.h
+++ b/arch/unicore32/include/asm/gpio.h
@@ -13,6 +13,12 @@
#ifndef __UNICORE_GPIO_H__
#define __UNICORE_GPIO_H__
+/* We implement a few ourself */
+#define gpio_get_value gpio_get_value
+#define gpio_set_value gpio_set_value
+#define gpio_to_irq gpio_to_irq
+#define irq_to_gpio irq_to_gpio
+
#include <linux/io.h>
#include <asm/irq.h>
#include <mach/hardware.h>
@@ -83,8 +89,6 @@ static inline void gpio_set_value(unsigned gpio, int value)
__gpio_set_value(gpio, value);
}
-#define gpio_cansleep __gpio_cansleep
-
static inline unsigned gpio_to_irq(unsigned gpio)
{
if ((gpio < IRQ_GPIOHIGH) && (FIELD(1, 1, gpio) & readl(GPIO_GPIR)))
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index 6fa90a8..99d44ce 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -1,5 +1,7 @@
include include/asm-generic/Kbuild.asm
+generic-y += gpio.h
+
header-y += boot.h
header-y += bootparam.h
header-y += debugreg.h
diff --git a/arch/x86/include/asm/gpio.h b/arch/x86/include/asm/gpio.h
deleted file mode 100644
index 91d915a..0000000
--- a/arch/x86/include/asm/gpio.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Generic GPIO API implementation for x86.
- *
- * Derived from the generic GPIO API for powerpc:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_X86_GPIO_H
-#define _ASM_X86_GPIO_H
-
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_X86_GPIO_H */
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild
index c68e168..7d52c50 100644
--- a/arch/xtensa/include/asm/Kbuild
+++ b/arch/xtensa/include/asm/Kbuild
@@ -1 +1,3 @@
include include/asm-generic/Kbuild.asm
+
+generic-y += gpio.h
diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h
deleted file mode 100644
index a8c9fc4..0000000
--- a/arch/xtensa/include/asm/gpio.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Generic GPIO API implementation for xtensa.
- *
- * Stolen from x86, which is derived from the generic GPIO API for powerpc:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_XTENSA_GPIO_H
-#define _ASM_XTENSA_GPIO_H
-
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-/*
- * Not implemented, yet.
- */
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_XTENSA_GPIO_H */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index d494001..622851c 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -170,6 +170,29 @@ extern int __gpio_cansleep(unsigned gpio);
extern int __gpio_to_irq(unsigned gpio);
+#ifndef gpio_get_value
+#define gpio_get_value(gpio) __gpio_get_value(gpio)
+#endif
+
+#ifndef gpio_set_value
+#define gpio_set_value(gpio, value) __gpio_set_value(gpio, value)
+#endif
+
+#ifndef gpio_cansleep
+#define gpio_cansleep(gpio) __gpio_cansleep(gpio)
+#endif
+
+#ifndef gpio_to_irq
+#define gpio_to_irq(gpio) __gpio_to_irq(gpio)
+#endif
+
+#ifndef irq_to_gpio
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+#endif
+
/**
* struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number
--
1.7.6.1
^ permalink raw reply related
* Re: [PATCH 2/2 v3] net/smsc911x: Add regulator support
From: Mike Frysinger @ 2011-10-27 22:43 UTC (permalink / raw)
To: Mark Brown
Cc: Linus Walleij, netdev, Steve Glendinning, Mathieu Poirer,
Robert Marklund, Paul Mundt, linux-sh, Sascha Hauer,
Tony Lindgren, linux-omap, uclinux-dist-devel, Linus Walleij
In-Reply-To: <20111027214241.GA11534@opensource.wolfsonmicro.com>
On Thu, Oct 27, 2011 at 23:42, Mark Brown wrote:
> On Thu, Oct 27, 2011 at 10:59:14PM +0200, Mike Frysinger wrote:
>> i saw that !CONFIG_REGULATOR works great. my concern is that these
>> boards don't define any regulators for smsc resources, so if
>> CONFIG_REGULATOR is enabled to test out unrelated daughter cards, i
>> don't want the network driver suddenly failing. Linus' comments
>> suggest that this is what would happen unless each board file has its
>> smsc platform resources extended. maybe i misunderstood what he was saying ?
>
> That's the case that's handled by CONFIG_REGULATOR_DUMMY - if the lookup
> fails the core will provide a virtual regulator to the consumer. If
> you're running a setup like that you probably want to enable dummy
> regulators anyway.
ok, if people configuring need only select that Kconfig symbol to make
it work, i'm fine with things. thanks for the explanation.
-mike
^ permalink raw reply
* Re: [PATCH 2/2 v3] net/smsc911x: Add regulator support
From: Mark Brown @ 2011-10-27 21:42 UTC (permalink / raw)
To: Mike Frysinger
Cc: Linus Walleij, netdev, Steve Glendinning, Mathieu Poirer,
Robert Marklund, Paul Mundt, linux-sh, Sascha Hauer,
Tony Lindgren, linux-omap, uclinux-dist-devel, Linus Walleij
In-Reply-To: <CAJaTeTpzFOdgqGH3vDWY8Mdx7zra8R9nUQYHgsEBfy_yGkEWOw@mail.gmail.com>
On Thu, Oct 27, 2011 at 10:59:14PM +0200, Mike Frysinger wrote:
> i saw that !CONFIG_REGULATOR works great. my concern is that these
> boards don't define any regulators for smsc resources, so if
> CONFIG_REGULATOR is enabled to test out unrelated daughter cards, i
> don't want the network driver suddenly failing. Linus' comments
> suggest that this is what would happen unless each board file has its
> smsc platform resources extended. maybe i misunderstood what he was saying ?
That's the case that's handled by CONFIG_REGULATOR_DUMMY - if the lookup
fails the core will provide a virtual regulator to the consumer. If
you're running a setup like that you probably want to enable dummy
regulators anyway.
^ permalink raw reply
* Re: [PATCH 2/2 v3] net/smsc911x: Add regulator support
From: Mike Frysinger @ 2011-10-27 20:59 UTC (permalink / raw)
To: Mark Brown
Cc: Linus Walleij, netdev, Steve Glendinning, Mathieu Poirer,
Robert Marklund, Paul Mundt, linux-sh, Sascha Hauer,
Tony Lindgren, linux-omap, uclinux-dist-devel, Linus Walleij
In-Reply-To: <20111027154638.GA16946@sirena.org.uk>
On Thu, Oct 27, 2011 at 17:46, Mark Brown wrote:
> On Thu, Oct 27, 2011 at 03:21:47PM +0200, Mike Frysinger wrote:
>> my gut reaction: smsc911x is working just fine without regulator
>> support for many people, so why do we suddenly need to make it a
>> requirement ? this is a fairly small amount of code, so adding a
>> smsc911x Kconfig symbol to control the regulator support seems like
>> overkill. only other option would be to change the patch to not make
>> missing regulators non-fatal. so i'd probably lean towards the latter
>> (and it sounds like you changed this with earlier versions).
>
> The regulator API contains a series of generic facilities for stubbing
> itself out when not in use - there's no need for individual drivers to
> worry about this stuff, they should just rely on the framework. The
> main one at the minute is REGULATOR_DUMMY which does what you suggest
> and makes regulator_get() never fail.
i saw that !CONFIG_REGULATOR works great. my concern is that these
boards don't define any regulators for smsc resources, so if
CONFIG_REGULATOR is enabled to test out unrelated daughter cards, i
don't want the network driver suddenly failing. Linus' comments
suggest that this is what would happen unless each board file has its
smsc platform resources extended. maybe i misunderstood what he was saying ?
-mike
^ 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