* Re: [RFC PATCH v2 3/4] powerpc: refactor of_get_cpu_node to support other architectures
From: Mark Rutland @ 2013-08-22 13:59 UTC (permalink / raw)
To: Sudeep KarkadaNagesha
Cc: Jonas Bonn, devicetree@vger.kernel.org, Michal Simek,
Lorenzo Pieralisi, linux-pm@vger.kernel.org, Tomasz Figa,
rob.herring@calxeda.com, linux-kernel@vger.kernel.org,
Rafael J. Wysocki, Rob Herring, grant.likely@linaro.org,
linuxppc-dev@lists.ozlabs.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <521223FA.5050903@arm.com>
On Mon, Aug 19, 2013 at 02:56:10PM +0100, Sudeep KarkadaNagesha wrote:
> On 19/08/13 14:02, Rob Herring wrote:
> > On 08/19/2013 05:19 AM, Mark Rutland wrote:
> >> On Sat, Aug 17, 2013 at 11:09:36PM +0100, Benjamin Herrenschmidt wrote:
> >>> On Sat, 2013-08-17 at 12:50 +0200, Tomasz Figa wrote:
> >>>> I wonder how would this handle uniprocessor ARM (pre-v7) cores, for
> >>>> which
> >>>> the updated bindings[1] define #address-cells = <0> and so no reg
> >>>> property.
> >>>>
> >>>> [1] - http://thread.gmane.org/gmane.linux.ports.arm.kernel/260795
> >>>
> >>> Why did you do that in the binding ? That sounds like looking to create
> >>> problems ...
> >>>
> >>> Traditionally, UP setups just used "0" as the "reg" property on other
> >>> architectures, why do differently ?
> >>
> >> The decision was taken because we defined our reg property to refer to
> >> the MPIDR register's Aff{2,1,0} bitfields, and on UP cores before v7
> >> there's no MPIDR register at all. Given there can only be a single CPU
> >> in that case, describing a register that wasn't present didn't seem
> >> necessary or helpful.
> >
> > What exactly reg represents is up to the binding definition, but it
> > still should be present IMO. I don't see any issue with it being
> > different for pre-v7.
> >
> Yes it's better to have 'reg' with value 0 than not having it.
> Otherwise this generic of_get_cpu_node implementation would need some
> _hack_ to handle that case.
I'm not sure that having some code to handle a difference in standard
between two architectures is a hack. If anything, I'd argue encoding a
reg of 0 that corresponds to a nonexistent MPIDR value (given that's
what the reg property is defined to map to on ARM) is more of a hack ;)
I'm not averse to having a reg value of 0 for this case, but given that
there are existing devicetrees without it, requiring a reg property will
break compatibility with them.
Mark.
^ permalink raw reply
* [GIT PULL v2] DT/core: cpu_ofnode updates for v3.12
From: Sudeep KarkadaNagesha @ 2013-08-22 13:57 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Jonas Bonn, devicetree@vger.kernel.org, monstr@monstr.eu,
linux-pm@vger.kernel.org, Sudeep.KarkadaNagesha,
linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
arm@kernel.org, Viresh Kumar, linuxppc-dev@lists.ozlabs.org,
linux-arm-kernel@lists.infradead.org
Hi Rafael,
Here is the v2 of the pull request for cpu of_node updates for v3.12
It includes ACK for all the new changes since v1(mainly from Ben for
PPC). Currently there's trivial conflict with today's linux-next in 3
files. Let me know if you need me to rebase this on any particular
branch if needed.
Regards,
Sudeep
The following changes since commit b36f4be3de1b123d8601de062e7dbfc904f305fb=
:
Linux 3.11-rc6 (2013-08-18 14:36:53 -0700)
are available in the git repository at:
git://linux-arm.org/linux-skn.git cpu_of_node
for you to fetch changes up to 1037b2752345cc5666e90b711a913ab2ae6c5920:
cpufreq: pmac32-cpufreq: remove device tree parsing for cpu nodes
(2013-08-21 10:29:56 +0100)
----------------------------------------------------------------
Sudeep KarkadaNagesha (19):
microblaze: remove undefined of_get_cpu_node declaration
openrisc: remove undefined of_get_cpu_node declaration
powerpc: refactor of_get_cpu_node to support other architectures
of: move of_get_cpu_node implementation to DT core library
ARM: DT/kernel: define ARM specific arch_match_cpu_phys_id
driver/core: cpu: initialize of_node in cpu's device struture
of/device: add helper to get cpu device node from logical cpu index
ARM: topology: remove hwid/MPIDR dependency from cpu_capacity
ARM: mvebu: remove device tree parsing for cpu nodes
drivers/bus: arm-cci: avoid parsing DT for cpu device nodes
cpufreq: imx6q-cpufreq: remove device tree parsing for cpu nodes
cpufreq: cpufreq-cpu0: remove device tree parsing for cpu nodes
cpufreq: highbank-cpufreq: remove device tree parsing for cpu nodes
cpufreq: spear-cpufreq: remove device tree parsing for cpu nodes
cpufreq: kirkwood-cpufreq: remove device tree parsing for cpu nodes
cpufreq: arm_big_little: remove device tree parsing for cpu nodes
cpufreq: maple-cpufreq: remove device tree parsing for cpu nodes
cpufreq: pmac64-cpufreq: remove device tree parsing for cpu nodes
cpufreq: pmac32-cpufreq: remove device tree parsing for cpu nodes
arch/arm/kernel/devtree.c | 5 ++
arch/arm/kernel/topology.c | 61 +++++-----------
arch/arm/mach-imx/mach-imx6q.c | 3 +-
arch/arm/mach-mvebu/platsmp.c | 51 ++++++-------
arch/microblaze/include/asm/prom.h | 3 -
arch/openrisc/include/asm/prom.h | 3 -
arch/powerpc/include/asm/prom.h | 3 -
arch/powerpc/kernel/prom.c | 43 +-----------
drivers/base/cpu.c | 2 +
drivers/bus/arm-cci.c | 28 ++------
drivers/cpufreq/arm_big_little_dt.c | 40 ++++-------
drivers/cpufreq/cpufreq-cpu0.c | 23 +-----
drivers/cpufreq/highbank-cpufreq.c | 18 ++---
drivers/cpufreq/imx6q-cpufreq.c | 4 +-
drivers/cpufreq/kirkwood-cpufreq.c | 8 ++-
drivers/cpufreq/maple-cpufreq.c | 23 +-----
drivers/cpufreq/pmac32-cpufreq.c | 5 +-
drivers/cpufreq/pmac64-cpufreq.c | 47 +++---------
drivers/cpufreq/spear-cpufreq.c | 4 +-
drivers/of/base.c | 95 ++++++++++++++++++++++++
include/linux/cpu.h | 1 +
include/linux/of.h | 7 ++
include/linux/of_device.h | 15 ++++
23 files changed, 226 insertions(+), 266 deletions(-)
^ permalink raw reply
* Re: [PATCH 3/4] powerpc/booke64: Use appropriate -mcpu
From: Rojhalat Ibrahim @ 2013-08-22 13:56 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Scott Wood, Catalin Udma
In-Reply-To: <1377051162-2588-4-git-send-email-scottwood@freescale.com>
Just out of curiosity: What's the difference (if any) between -mcpu=e500mc64
and -mcpu=e5500? AFAIK -mcpu=e500mc64 is supported by gcc since at least
version 4.6 whereas -mcpu=e5500 is only supported since gcc 4.8. But is there
actually any difference?
Rojhalat
On Tuesday 20 August 2013 21:12:41 Scott Wood wrote:
> By default use -mcpu=powerpc64 rather than -mtune=power7
>
> Add options for e5500/e6500, with fallbacks for older compilers.
>
> Hide the POWER cpu options in booke configs.
>
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> arch/powerpc/Makefile | 9 +++++++++
> arch/powerpc/platforms/Kconfig.cputype | 13 +++++++++++++
> 2 files changed, 22 insertions(+)
>
> diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
> index 6930c93..32dfd5d 100644
> --- a/arch/powerpc/Makefile
> +++ b/arch/powerpc/Makefile
> @@ -88,13 +88,22 @@ CFLAGS-$(CONFIG_PPC64) += $(call
> cc-option,-mcmodel=medium,-mminimal-toc) CFLAGS-$(CONFIG_PPC64) += $(call
> cc-option,-mno-pointers-to-nested-functions) CFLAGS-$(CONFIG_PPC32) :=
> -ffixed-r2 -mmultiple
>
> +ifeq ($(CONFIG_PPC_BOOK3S_64),y)
> CFLAGS-$(CONFIG_GENERIC_CPU) += $(call
> cc-option,-mtune=power7,-mtune=power4) +else
> +CFLAGS-$(CONFIG_GENERIC_CPU) += -mcpu=powerpc64
> +endif
> +
> CFLAGS-$(CONFIG_CELL_CPU) += $(call cc-option,-mcpu=cell)
> CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
> CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
> CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
> CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
>
> +E5500_CPU := $(call cc-option,-mcpu=e500mc64,-mcpu=powerpc64)
> +CFLAGS-$(CONFIG_E5500_CPU) += $(E5500_CPU)
> +CFLAGS-$(CONFIG_E6500_CPU) += $(call cc-option,-mcpu=e6500,$(E5500_CPU))
> +
> CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
>
> KBUILD_CPPFLAGS += -Iarch/$(ARCH)
> diff --git a/arch/powerpc/platforms/Kconfig.cputype
> b/arch/powerpc/platforms/Kconfig.cputype index 47d9a03..6704e2e 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -96,18 +96,31 @@ config GENERIC_CPU
>
> config CELL_CPU
> bool "Cell Broadband Engine"
> + depends on PPC_BOOK3S_64
>
> config POWER4_CPU
> bool "POWER4"
> + depends on PPC_BOOK3S_64
>
> config POWER5_CPU
> bool "POWER5"
> + depends on PPC_BOOK3S_64
>
> config POWER6_CPU
> bool "POWER6"
> + depends on PPC_BOOK3S_64
>
> config POWER7_CPU
> bool "POWER7"
> + depends on PPC_BOOK3S_64
> +
> +config E5500_CPU
> + bool "Freescale e5500"
> + depends on E500
> +
> +config E6500_CPU
> + bool "Freescale e6500"
> + depends on E500
>
> endchoice
^ permalink raw reply
* Re: [PATCH v4 03/19] powerpc: refactor of_get_cpu_node to support other architectures
From: Sudeep KarkadaNagesha @ 2013-08-22 13:29 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Jonas Bonn, devicetree@vger.kernel.org, Michal Simek,
linux-pm@vger.kernel.org, Sudeep KarkadaNagesha, Viresh Kumar,
linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
Rafael J. Wysocki, Greg Kroah-Hartman, grant.likely@linaro.org,
linuxppc-dev@lists.ozlabs.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <1377152143.25016.289.camel@pasglop>
On 22/08/13 07:15, Benjamin Herrenschmidt wrote:
> On Tue, 2013-08-20 at 10:30 +0100, Sudeep KarkadaNagesha wrote:
>> From: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
>>
>> Currently different drivers requiring to access cpu device node are
>> parsing the device tree themselves. Since the ordering in the DT need
>> not match the logical cpu ordering, the parsing logic needs to consider
>> that. However, this has resulted in lots of code duplication and in some
>> cases even incorrect logic.
>>
>> It's better to consolidate them by adding support for getting cpu
>> device node for a given logical cpu index in DT core library. However
>> logical to physical index mapping can be architecture specific.
>>
>> PowerPC has it's own implementation to get the cpu node for a given
>> logical index.
>>
>> This patch refactors the current implementation of of_get_cpu_node.
>> This in preparation to move the implementation to DT core library.
>> It separates out the logical to physical mapping so that a default
>> matching of the physical id to the logical cpu index can be added
>> when moved to common code. Architecture specific code can override it.
>=20
> So the patch unfortunately collides with other changes in powerpc -next,
> though it's not a huge deal and not hard to fixup, but expect Linus
> to tick unless we sort it out some other way.
>=20
> Appart from that, it's fine, builds on all my test configs and doesn't
> seem to negatively impact things as far as I can tell so far...
>=20
> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>=20
Hi Ben,
Thanks a lot for testing and ACK.
I will check with Rafael about these (trivial) conflicts.
Regards,
Sudeep
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Mark Rutland @ 2013-08-22 12:09 UTC (permalink / raw)
To: Mike Turquette, Sascha Hauer
Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
lars@metafoo.de, ian.campbell@citrix.com, Pawel Moll,
swarren@wwwdotorg.org, festevam@gmail.com, Nicolin Chen,
Tomasz Figa, rob.herring@calxeda.com, timur@tabi.org,
broonie@kernel.org, p.zabel@pengutronix.de, galak@codeaurora.org,
shawn.guo@linaro.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130822071910.8231.47324@quantum>
On Thu, Aug 22, 2013 at 08:19:10AM +0100, Mike Turquette wrote:
> Quoting Tomasz Figa (2013-08-21 14:34:55)
> > On Wednesday 21 of August 2013 09:50:15 Mark Rutland wrote:
> > > On Tue, Aug 20, 2013 at 01:06:25AM +0100, Mike Turquette wrote:
> > > > Quoting Mark Rutland (2013-08-19 02:35:43)
> > > >
> > > > > On Sat, Aug 17, 2013 at 04:17:18PM +0100, Tomasz Figa wrote:
> > > > > > On Saturday 17 of August 2013 16:53:16 Sascha Hauer wrote:
> > > > > > > On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > > > > > > > > Also I would make this option required. Use a dummy
> > > > > > > > > > > clock for
> > > > > > > > > > > mux
> > > > > > > > > > > inputs that are grounded for a specific SoC.
> > > > > > > > > >
> > > > > > > > > > Some clocks are not from CCM and we haven't defined in
> > > > > > > > > > imx6q-clk.txt,
> > > > > > > > > > so in most cases we can't provide a phandle for them, eg:
> > > > > > > > > > spdif_ext.
> > > > > > > > > > I think it's a bit hard to force it to be 'required'. An
> > > > > > > > > > 'optional'
> > > > > > > > > > looks more flexible to me and a default one is ensured
> > > > > > > > > > even if
> > > > > > > > > > it's
> > > > > > > > > > missing.
> > > > > > > > >
> > > > > > > > > <&clks 0> is the dummy clock. This can be used for all input
> > > > > > > > > clocks
> > > > > > > > > not
> > > > > > > > > defined by the SoC.
> > > > > > > >
> > > > > > > > Where does this assumption come from? Is it documented
> > > > > > > > anywhere?
> > > > > > >
> > > > > > > This is how all i.MX clock bindings currently are. See
> > > > > > > Documentation/devicetree/bindings/clock/imx*-clock.txt
> > > > > >
> > > > > > OK, thanks.
> > > > > >
> > > > > > I guess we need some discussion on dummy clocks vs skipped clocks.
> > > > > > I think we want some consistency on this, don't we?
> > > > > >
> > > > > > If we really need a dummy clock, then we might also want a generic
> > > > > > way to specify it.
> > > > >
> > > > > What do we actually mean by a "dummy clock"? We already have
> > > > > bindings
> > > > > for "fixed-clock" and co friends describe relatively simple
> > > > > preconfigured clocks.
> > > >
> > > > Some platforms have a fake clock which defines noops callbacks and
> > > > basically doesn't do anything. This is analogous to the dummy
> > > > regulator
> > > > implementation. A central one could be registered by the clock core,
> > > > as
> > > > is done by the regulator core.
> > >
> > > When you say some platforms, you presumably mean the platform code in
> > > Linux? A dummy clock sounds like a completely Linux-specific abstraction
> > > rather than a description of the hardware, and I don't see why we need
> > > that in the DT:
> > >
> > > * If a clock is wired up and running (as presumably the dummy clock is),
> > > then surely it's a fixed-clock (it's running, we and we have no control
> > > over it, but we presumably know its rate) and can be described as such?
> > >
> > > * If no clock is wired up, then we should be able to describe that. If a
> > > driver believes that a clock is required when it isn't (for some level
> > > of functionality), then that driver should be fixed up to support the
> > > clock as being optional.
> > >
> > > Am I missing something?
> >
> > I second that.
> >
> > Moreover, I don't think that device tree should deal with dummy anything.
> > It should be able to describe hardware that is available on given system,
> > not list what hardware is not available.
>
> I wasn't clear. The dummy clock IS a completely Linux-specific
> abstraction.
>
> I'm not advocating a dummy clock in DT. I am advocating consolidation of
> the implementation of a clock that does nothing into the clock core.
> This code could easily live in drivers/clk/clk.c instead of having
> everyone open-code it.
>
> As far as specifying a dummy clock in DT? I dunno. DT should describe
> real hardware so there isn't much use for a dummy clock.
Sorry, I misunderstood. Good to hear we're on the same page :)
>
> I'm guessing one of the reasons for such a clock are drivers do not
> honor the clk.h api and they freak out when clk_get gives them a NULL
> pointer?
I'm not sure. Sascha, could you shed some light on the matter?
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH v10 2/2] ASoC: fsl: Add S/PDIF machine driver
From: Nicolin Chen @ 2013-08-22 11:40 UTC (permalink / raw)
To: Stephen Warren
Cc: mark.rutland, devicetree, alsa-devel, lars, festevam, s.hauer,
timur, rob.herring, tomasz.figa, broonie, p.zabel, R65777,
shawn.guo, linuxppc-dev
In-Reply-To: <52150763.8020707@wwwdotorg.org>
Hi Stephen,
On Wed, Aug 21, 2013 at 12:30:59PM -0600, Stephen Warren wrote:
> I still don't think those two properties are correct.
>
> Exactly what node will those phandles point at?
>
> There definitely should not be a DT node for any "dummy CODEC",
> irrespective of whether this binding calls the other node a "CODEC" or a
> "dummy CODEC".
>
> If these properties are to contain phandles, it would be acceptable for
> the referenced node to be:
>
> * A node representing the physical connector/jack on the board.
>
> * A node representing some other IP block on the board, such as an HDMI
> encoder/display-controller
>
> I think those options are unlikely in general, so I think instead these
> properties should just be Boolean indicating that "something" is
> connector to the S/PDIF RX/TX, without specifying what that "something"
> is. It doesn't matter what at least in the connector/jack case, although
> perhaps it does in the HDMI encoder/display-controller?
Documentation/devicetree/bindings/sound/spdif-receiver.txt
If I understand correctly, this doc for the dummy codec should be invalid?
But this patch, the spdif machine driver, is based on this codec driver,
pls check the following code:
164 + codec_rx_np = of_parse_phandle(np, "spdif-receiver", 0);
165 + if (codec_rx_np) {
169 + data->dai[num_links].codec_of_node = codec_rx_np;
173 + }
Accordingly, the binding I planned to add in DT:
27 + spdif_rx_codec: spdif-receiver {
28 + compatible = "linux,spdif-dir";
29 + };
30 +
31 + sound-spdif {
32 + compatible = "fsl,imx-audio-spdif",
33 + "fsl,imx-sabreauto-spdif";
34 + model = "imx-spdif";
35 + spdif-controller = <&spdif>;
37 + spdif-receiver = <&spdif_rx_codec>;
38 + };
So if the DT can't allow me to include this codec node, how could I
handle it in the current baseline.
Could you please directly provide me a nicer means? Or maybe just an
eclectic way for everyone, since it doesn't look like we have a perfect
solution right now.
Thank you so much.
Nicolin
^ permalink raw reply
* [PATCH] powerpc/kvm: Copy the pvr value after memset
From: Aneesh Kumar K.V @ 2013-08-22 11:38 UTC (permalink / raw)
To: benh, paulus, agraf; +Cc: linuxppc-dev, Aneesh Kumar K.V, kvm-ppc
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Otherwise we would clear the pvr value
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/kvm/book3s_hv.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 2efa9dd..dd1b72c 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -680,13 +680,12 @@ static int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
}
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
- struct kvm_sregs *sregs)
+ struct kvm_sregs *sregs)
{
int i;
- sregs->pvr = vcpu->arch.pvr;
-
memset(sregs, 0, sizeof(struct kvm_sregs));
+ sregs->pvr = vcpu->arch.pvr;
for (i = 0; i < vcpu->arch.slb_max; i++) {
sregs->u.s.ppc64.slb[i].slbe = vcpu->arch.slb[i].orige;
sregs->u.s.ppc64.slb[i].slbv = vcpu->arch.slb[i].origv;
@@ -696,7 +695,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
- struct kvm_sregs *sregs)
+ struct kvm_sregs *sregs)
{
int i, j;
--
1.8.1.2
^ permalink raw reply related
* [PATCH] powerpc/kvm: Handle the boundary condition correctly
From: Aneesh Kumar K.V @ 2013-08-22 11:37 UTC (permalink / raw)
To: benh, paulus, agraf; +Cc: linuxppc-dev, Aneesh Kumar K.V, kvm-ppc
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
We should be able to copy upto count bytes
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
arch/powerpc/kvm/book3s_64_mmu_hv.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 710d313..0ae6bb6 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -1362,7 +1362,7 @@ static ssize_t kvm_htab_read(struct file *file, char __user *buf,
lbuf = (unsigned long __user *)buf;
nb = 0;
- while (nb + sizeof(hdr) + HPTE_SIZE < count) {
+ while (nb + sizeof(hdr) + HPTE_SIZE <= count) {
/* Initialize header */
hptr = (struct kvm_get_htab_header __user *)buf;
hdr.n_valid = 0;
@@ -1385,7 +1385,7 @@ static ssize_t kvm_htab_read(struct file *file, char __user *buf,
/* Grab a series of valid entries */
while (i < kvm->arch.hpt_npte &&
hdr.n_valid < 0xffff &&
- nb + HPTE_SIZE < count &&
+ nb + HPTE_SIZE <= count &&
record_hpte(flags, hptp, hpte, revp, 1, first_pass)) {
/* valid entry, write it out */
++hdr.n_valid;
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH V4 3/5] powerpc/cpuidle: Generic powerpc backend cpuidle driver.
From: Bartlomiej Zolnierkiewicz @ 2013-08-22 10:56 UTC (permalink / raw)
To: Deepthi Dharwar
Cc: rjw, daniel.lezcano, linux-kernel, dongsheng.wang, preeti,
srivatsa.bhat, scottwood, linux-pm, linuxppc-dev
In-Reply-To: <20130822053026.23277.8122.stgit@deepthi.in.ibm.com>
Hi,
On Thursday, August 22, 2013 11:00:29 AM Deepthi Dharwar wrote:
> This patch involves moving the current pseries_idle backend driver code
> from pseries/processor_idle.c to drivers/cpuidle/cpuidle-powerpc.c,
> and making the backend code generic enough to be able to extend this
> driver code for both powernv and pseries.
>
> It enables the support for pseries platform, such that going forward the same code
> with minimal efforts can be re-used for a common driver on powernv
> and can be further extended to support cpuidle idle state mgmt for the rest
> of the powerpc platforms in the future. This removes a lot of code duplicacy,
> making the code elegant.
This patch mixes the code movement with the actual code changes which is
not a good practice as it makes review more difficult and is generally bad
from the long term maintainance POV.
Please split this patch on code movement and code changes parts.
V4 of this patch now also seems to contain changes which I posted on
Tuesday as a part of dev->state_count removal patchset:
http://permalink.gmane.org/gmane.linux.power-management.general/37392
http://permalink.gmane.org/gmane.linux.power-management.general/37393
so some work probably got duplicated. :(
Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics
> Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
> ---
> arch/powerpc/include/asm/paca.h | 23 +
> arch/powerpc/include/asm/processor.h | 2
> arch/powerpc/platforms/pseries/Kconfig | 9 -
> arch/powerpc/platforms/pseries/Makefile | 1
> arch/powerpc/platforms/pseries/processor_idle.c | 360 -----------------------
> drivers/cpuidle/Kconfig | 7
> drivers/cpuidle/Makefile | 2
> drivers/cpuidle/cpuidle-powerpc.c | 304 +++++++++++++++++++
> 8 files changed, 337 insertions(+), 371 deletions(-)
> delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
> create mode 100644 drivers/cpuidle/cpuidle-powerpc.c
>
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index 77c91e7..7bd83ff 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -175,6 +175,29 @@ extern void setup_paca(struct paca_struct *new_paca);
> extern void allocate_pacas(void);
> extern void free_unused_pacas(void);
>
> +#ifdef CONFIG_PPC_BOOK3S
> +#define get_lppaca_is_shared_proc() get_paca()->lppaca_ptr->shared_proc
> +static inline void set_lppaca_idle(u8 idle)
> +{
> + get_paca()->lppaca_ptr->idle = idle;
> +}
> +
> +static inline void add_lppaca_wait_state(u64 cycles)
> +{
> + get_paca()->lppaca_ptr->wait_state_cycles += cycles;
> +}
> +
> +static inline void set_lppaca_donate_dedicated_cpu(u8 value)
> +{
> + get_paca()->lppaca_ptr->donate_dedicated_cpu = value;
> +}
> +#else
> +#define get_lppaca_is_shared_proc() -1
> +static inline void set_lppaca_idle(u8 idle) { }
> +static inline void add_lppaca_wait_state(u64 cycles) { }
> +static inline void set_lppaca_donate_dedicated_cpu(u8 value) { }
> +#endif
> +
> #else /* CONFIG_PPC64 */
>
> static inline void allocate_pacas(void) { };
> diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
> index e378ccc..5f57c56 100644
> --- a/arch/powerpc/include/asm/processor.h
> +++ b/arch/powerpc/include/asm/processor.h
> @@ -430,7 +430,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
> extern int powersave_nap; /* set if nap mode can be used in idle loop */
> extern void power7_nap(void);
>
> -#ifdef CONFIG_PSERIES_IDLE
> +#ifdef CONFIG_CPU_IDLE_POWERPC
> extern void update_smt_snooze_delay(int cpu, int residency);
> #else
> static inline void update_smt_snooze_delay(int cpu, int residency) {}
> diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
> index 62b4f80..bb59bb0 100644
> --- a/arch/powerpc/platforms/pseries/Kconfig
> +++ b/arch/powerpc/platforms/pseries/Kconfig
> @@ -119,12 +119,3 @@ config DTL
> which are accessible through a debugfs file.
>
> Say N if you are unsure.
> -
> -config PSERIES_IDLE
> - bool "Cpuidle driver for pSeries platforms"
> - depends on CPU_IDLE
> - depends on PPC_PSERIES
> - default y
> - help
> - Select this option to enable processor idle state management
> - through cpuidle subsystem.
> diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
> index 8ae0103..4b22379 100644
> --- a/arch/powerpc/platforms/pseries/Makefile
> +++ b/arch/powerpc/platforms/pseries/Makefile
> @@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
> obj-$(CONFIG_CMM) += cmm.o
> obj-$(CONFIG_DTL) += dtl.o
> obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
> -obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o
>
> ifeq ($(CONFIG_PPC_PSERIES),y)
> obj-$(CONFIG_SUSPEND) += suspend.o
> diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
> deleted file mode 100644
> index c905b99..0000000
> --- a/arch/powerpc/platforms/pseries/processor_idle.c
> +++ /dev/null
> @@ -1,360 +0,0 @@
> -/*
> - * processor_idle - idle state cpuidle driver.
> - * Adapted from drivers/idle/intel_idle.c and
> - * drivers/acpi/processor_idle.c
> - *
> - */
> -
> -#include <linux/kernel.h>
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/moduleparam.h>
> -#include <linux/cpuidle.h>
> -#include <linux/cpu.h>
> -#include <linux/notifier.h>
> -
> -#include <asm/paca.h>
> -#include <asm/reg.h>
> -#include <asm/machdep.h>
> -#include <asm/firmware.h>
> -#include <asm/runlatch.h>
> -#include <asm/plpar_wrappers.h>
> -
> -struct cpuidle_driver pseries_idle_driver = {
> - .name = "pseries_idle",
> - .owner = THIS_MODULE,
> -};
> -
> -#define MAX_IDLE_STATE_COUNT 2
> -
> -static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
> -static struct cpuidle_device __percpu *pseries_cpuidle_devices;
> -static struct cpuidle_state *cpuidle_state_table;
> -
> -static inline void idle_loop_prolog(unsigned long *in_purr)
> -{
> - *in_purr = mfspr(SPRN_PURR);
> - /*
> - * Indicate to the HV that we are idle. Now would be
> - * a good time to find other work to dispatch.
> - */
> - get_lppaca()->idle = 1;
> -}
> -
> -static inline void idle_loop_epilog(unsigned long in_purr)
> -{
> - get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
> - get_lppaca()->idle = 0;
> -}
> -
> -static int snooze_loop(struct cpuidle_device *dev,
> - struct cpuidle_driver *drv,
> - int index)
> -{
> - unsigned long in_purr;
> - int cpu = dev->cpu;
> -
> - idle_loop_prolog(&in_purr);
> - local_irq_enable();
> - set_thread_flag(TIF_POLLING_NRFLAG);
> -
> - while ((!need_resched()) && cpu_online(cpu)) {
> - ppc64_runlatch_off();
> - HMT_low();
> - HMT_very_low();
> - }
> -
> - HMT_medium();
> - clear_thread_flag(TIF_POLLING_NRFLAG);
> - smp_mb();
> -
> - idle_loop_epilog(in_purr);
> -
> - return index;
> -}
> -
> -static void check_and_cede_processor(void)
> -{
> - /*
> - * Ensure our interrupt state is properly tracked,
> - * also checks if no interrupt has occurred while we
> - * were soft-disabled
> - */
> - if (prep_irq_for_idle()) {
> - cede_processor();
> -#ifdef CONFIG_TRACE_IRQFLAGS
> - /* Ensure that H_CEDE returns with IRQs on */
> - if (WARN_ON(!(mfmsr() & MSR_EE)))
> - __hard_irq_enable();
> -#endif
> - }
> -}
> -
> -static int dedicated_cede_loop(struct cpuidle_device *dev,
> - struct cpuidle_driver *drv,
> - int index)
> -{
> - unsigned long in_purr;
> -
> - idle_loop_prolog(&in_purr);
> - get_lppaca()->donate_dedicated_cpu = 1;
> -
> - ppc64_runlatch_off();
> - HMT_medium();
> - check_and_cede_processor();
> -
> - get_lppaca()->donate_dedicated_cpu = 0;
> -
> - idle_loop_epilog(in_purr);
> -
> - return index;
> -}
> -
> -static int shared_cede_loop(struct cpuidle_device *dev,
> - struct cpuidle_driver *drv,
> - int index)
> -{
> - unsigned long in_purr;
> -
> - idle_loop_prolog(&in_purr);
> -
> - /*
> - * Yield the processor to the hypervisor. We return if
> - * an external interrupt occurs (which are driven prior
> - * to returning here) or if a prod occurs from another
> - * processor. When returning here, external interrupts
> - * are enabled.
> - */
> - check_and_cede_processor();
> -
> - idle_loop_epilog(in_purr);
> -
> - return index;
> -}
> -
> -/*
> - * States for dedicated partition case.
> - */
> -static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
> - { /* Snooze */
> - .name = "snooze",
> - .desc = "snooze",
> - .flags = CPUIDLE_FLAG_TIME_VALID,
> - .exit_latency = 0,
> - .target_residency = 0,
> - .enter = &snooze_loop },
> - { /* CEDE */
> - .name = "CEDE",
> - .desc = "CEDE",
> - .flags = CPUIDLE_FLAG_TIME_VALID,
> - .exit_latency = 10,
> - .target_residency = 100,
> - .enter = &dedicated_cede_loop },
> -};
> -
> -/*
> - * States for shared partition case.
> - */
> -static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
> - { /* Shared Cede */
> - .name = "Shared Cede",
> - .desc = "Shared Cede",
> - .flags = CPUIDLE_FLAG_TIME_VALID,
> - .exit_latency = 0,
> - .target_residency = 0,
> - .enter = &shared_cede_loop },
> -};
> -
> -void update_smt_snooze_delay(int cpu, int residency)
> -{
> - struct cpuidle_driver *drv = cpuidle_get_driver();
> - struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
> -
> - if (cpuidle_state_table != dedicated_states)
> - return;
> -
> - if (residency < 0) {
> - /* Disable the Nap state on that cpu */
> - if (dev)
> - dev->states_usage[1].disable = 1;
> - } else
> - if (drv)
> - drv->states[1].target_residency = residency;
> -}
> -
> -static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
> - unsigned long action, void *hcpu)
> -{
> - int hotcpu = (unsigned long)hcpu;
> - struct cpuidle_device *dev =
> - per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
> -
> - if (dev && cpuidle_get_driver()) {
> - switch (action) {
> - case CPU_ONLINE:
> - case CPU_ONLINE_FROZEN:
> - cpuidle_pause_and_lock();
> - cpuidle_enable_device(dev);
> - cpuidle_resume_and_unlock();
> - break;
> -
> - case CPU_DEAD:
> - case CPU_DEAD_FROZEN:
> - cpuidle_pause_and_lock();
> - cpuidle_disable_device(dev);
> - cpuidle_resume_and_unlock();
> - break;
> -
> - default:
> - return NOTIFY_DONE;
> - }
> - }
> - return NOTIFY_OK;
> -}
> -
> -static struct notifier_block setup_hotplug_notifier = {
> - .notifier_call = pseries_cpuidle_add_cpu_notifier,
> -};
> -
> -/*
> - * pseries_cpuidle_driver_init()
> - */
> -static int pseries_cpuidle_driver_init(void)
> -{
> - int idle_state;
> - struct cpuidle_driver *drv = &pseries_idle_driver;
> -
> - drv->state_count = 0;
> -
> - for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
> -
> - if (idle_state > max_idle_state)
> - break;
> -
> - /* is the state not enabled? */
> - if (cpuidle_state_table[idle_state].enter == NULL)
> - continue;
> -
> - drv->states[drv->state_count] = /* structure copy */
> - cpuidle_state_table[idle_state];
> -
> - drv->state_count += 1;
> - }
> -
> - return 0;
> -}
> -
> -/* pseries_idle_devices_uninit(void)
> - * unregister cpuidle devices and de-allocate memory
> - */
> -static void pseries_idle_devices_uninit(void)
> -{
> - int i;
> - struct cpuidle_device *dev;
> -
> - for_each_possible_cpu(i) {
> - dev = per_cpu_ptr(pseries_cpuidle_devices, i);
> - cpuidle_unregister_device(dev);
> - }
> -
> - free_percpu(pseries_cpuidle_devices);
> - return;
> -}
> -
> -/* pseries_idle_devices_init()
> - * allocate, initialize and register cpuidle device
> - */
> -static int pseries_idle_devices_init(void)
> -{
> - int i;
> - struct cpuidle_driver *drv = &pseries_idle_driver;
> - struct cpuidle_device *dev;
> -
> - pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
> - if (pseries_cpuidle_devices == NULL)
> - return -ENOMEM;
> -
> - for_each_possible_cpu(i) {
> - dev = per_cpu_ptr(pseries_cpuidle_devices, i);
> - dev->state_count = drv->state_count;
> - dev->cpu = i;
> - if (cpuidle_register_device(dev)) {
> - printk(KERN_DEBUG \
> - "cpuidle_register_device %d failed!\n", i);
> - return -EIO;
> - }
> - }
> -
> - return 0;
> -}
> -
> -/*
> - * pseries_idle_probe()
> - * Choose state table for shared versus dedicated partition
> - */
> -static int pseries_idle_probe(void)
> -{
> -
> - if (!firmware_has_feature(FW_FEATURE_SPLPAR))
> - return -ENODEV;
> -
> - if (cpuidle_disable != IDLE_NO_OVERRIDE)
> - return -ENODEV;
> -
> - if (max_idle_state == 0) {
> - printk(KERN_DEBUG "pseries processor idle disabled.\n");
> - return -EPERM;
> - }
> -
> - if (get_lppaca()->shared_proc)
> - cpuidle_state_table = shared_states;
> - else
> - cpuidle_state_table = dedicated_states;
> -
> - return 0;
> -}
> -
> -static int __init pseries_processor_idle_init(void)
> -{
> - int retval;
> -
> - retval = pseries_idle_probe();
> - if (retval)
> - return retval;
> -
> - pseries_cpuidle_driver_init();
> - retval = cpuidle_register_driver(&pseries_idle_driver);
> - if (retval) {
> - printk(KERN_DEBUG "Registration of pseries driver failed.\n");
> - return retval;
> - }
> -
> - retval = pseries_idle_devices_init();
> - if (retval) {
> - pseries_idle_devices_uninit();
> - cpuidle_unregister_driver(&pseries_idle_driver);
> - return retval;
> - }
> -
> - register_cpu_notifier(&setup_hotplug_notifier);
> - printk(KERN_DEBUG "pseries_idle_driver registered\n");
> -
> - return 0;
> -}
> -
> -static void __exit pseries_processor_idle_exit(void)
> -{
> -
> - unregister_cpu_notifier(&setup_hotplug_notifier);
> - pseries_idle_devices_uninit();
> - cpuidle_unregister_driver(&pseries_idle_driver);
> -
> - return;
> -}
> -
> -module_init(pseries_processor_idle_init);
> -module_exit(pseries_processor_idle_exit);
> -
> -MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
> -MODULE_DESCRIPTION("Cpuidle driver for POWER");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
> index 0e2cd5c..53ce03d 100644
> --- a/drivers/cpuidle/Kconfig
> +++ b/drivers/cpuidle/Kconfig
> @@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ
> help
> Select this to enable cpuidle on Xilinx Zynq processors.
>
> +config CPU_IDLE_POWERPC
> + bool "CPU Idle driver for POWERPC platforms"
> + depends on PPC_PSERIES || PPC_POWERNV
> + default y
> + help
> + Select this option to enable processor idle state management
> + for POWERPC platform.
> endif
>
> config ARCH_NEEDS_CPU_IDLE_COUPLED
> diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
> index 8767a7b..d12e205 100644
> --- a/drivers/cpuidle/Makefile
> +++ b/drivers/cpuidle/Makefile
> @@ -8,3 +8,5 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
> obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
> obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
> obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
> +
> +obj-$(CONFIG_CPU_IDLE_POWERPC) += cpuidle-powerpc.o
> diff --git a/drivers/cpuidle/cpuidle-powerpc.c b/drivers/cpuidle/cpuidle-powerpc.c
> new file mode 100644
> index 0000000..3662aba
> --- /dev/null
> +++ b/drivers/cpuidle/cpuidle-powerpc.c
> @@ -0,0 +1,304 @@
> +/*
> + * processor_idle - idle state cpuidle driver.
> + * Adapted from drivers/idle/intel_idle.c and
> + * drivers/acpi/processor_idle.c
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/moduleparam.h>
> +#include <linux/cpuidle.h>
> +#include <linux/cpu.h>
> +#include <linux/notifier.h>
> +
> +#include <asm/paca.h>
> +#include <asm/reg.h>
> +#include <asm/machdep.h>
> +#include <asm/firmware.h>
> +#include <asm/runlatch.h>
> +#include <asm/plpar_wrappers.h>
> +
> +struct cpuidle_driver powerpc_idle_driver = {
> + .name = "powerpc_idle",
> + .owner = THIS_MODULE,
> +};
> +
> +#define MAX_IDLE_STATE_COUNT 2
> +
> +static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
> +static struct cpuidle_state *cpuidle_state_table;
> +
> +static inline void idle_loop_prolog(unsigned long *in_purr)
> +{
> + *in_purr = mfspr(SPRN_PURR);
> + /*
> + * Indicate to the HV that we are idle. Now would be
> + * a good time to find other work to dispatch.
> + */
> + set_lppaca_idle(1);
> +}
> +
> +static inline void idle_loop_epilog(unsigned long in_purr)
> +{
> + add_lppaca_wait_state(mfspr(SPRN_PURR) - in_purr);
> + set_lppaca_idle(0);
> +}
> +
> +static int snooze_loop(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv,
> + int index)
> +{
> + unsigned long in_purr;
> +
> + idle_loop_prolog(&in_purr);
> + local_irq_enable();
> + set_thread_flag(TIF_POLLING_NRFLAG);
> +
> + while (!need_resched()) {
> + ppc64_runlatch_off();
> + HMT_low();
> + HMT_very_low();
> + }
> +
> + HMT_medium();
> + clear_thread_flag(TIF_POLLING_NRFLAG);
> + smp_mb();
> +
> + idle_loop_epilog(in_purr);
> +
> + return index;
> +}
> +
> +static void check_and_cede_processor(void)
> +{
> + /*
> + * Ensure our interrupt state is properly tracked,
> + * also checks if no interrupt has occurred while we
> + * were soft-disabled
> + */
> + if (prep_irq_for_idle()) {
> + cede_processor();
> +#ifdef CONFIG_TRACE_IRQFLAGS
> + /* Ensure that H_CEDE returns with IRQs on */
> + if (WARN_ON(!(mfmsr() & MSR_EE)))
> + __hard_irq_enable();
> +#endif
> + }
> +}
> +
> +static int dedicated_cede_loop(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv,
> + int index)
> +{
> + unsigned long in_purr;
> +
> + idle_loop_prolog(&in_purr);
> + set_lppaca_donate_dedicated_cpu(1);
> +
> + ppc64_runlatch_off();
> + HMT_medium();
> + check_and_cede_processor();
> +
> + set_lppaca_donate_dedicated_cpu(0);
> + idle_loop_epilog(in_purr);
> +
> + return index;
> +}
> +
> +static int shared_cede_loop(struct cpuidle_device *dev,
> + struct cpuidle_driver *drv,
> + int index)
> +{
> + unsigned long in_purr;
> +
> + idle_loop_prolog(&in_purr);
> +
> + /*
> + * Yield the processor to the hypervisor. We return if
> + * an external interrupt occurs (which are driven prior
> + * to returning here) or if a prod occurs from another
> + * processor. When returning here, external interrupts
> + * are enabled.
> + */
> + check_and_cede_processor();
> +
> + idle_loop_epilog(in_purr);
> +
> + return index;
> +}
> +
> +/*
> + * States for dedicated partition case.
> + */
> +static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
> + { /* Snooze */
> + .name = "snooze",
> + .desc = "snooze",
> + .flags = CPUIDLE_FLAG_TIME_VALID,
> + .exit_latency = 0,
> + .target_residency = 0,
> + .enter = &snooze_loop },
> + { /* CEDE */
> + .name = "CEDE",
> + .desc = "CEDE",
> + .flags = CPUIDLE_FLAG_TIME_VALID,
> + .exit_latency = 10,
> + .target_residency = 100,
> + .enter = &dedicated_cede_loop },
> +};
> +
> +/*
> + * States for shared partition case.
> + */
> +static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
> + { /* Shared Cede */
> + .name = "Shared Cede",
> + .desc = "Shared Cede",
> + .flags = CPUIDLE_FLAG_TIME_VALID,
> + .exit_latency = 0,
> + .target_residency = 0,
> + .enter = &shared_cede_loop },
> +};
> +
> +void update_smt_snooze_delay(int cpu, int residency)
> +{
> + struct cpuidle_driver *drv = cpuidle_get_driver();
> + struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
> +
> + if (cpuidle_state_table != dedicated_states)
> + return;
> +
> + if (residency < 0) {
> + /* Disable the Nap state on that cpu */
> + if (dev)
> + dev->states_usage[1].disable = 1;
> + } else
> + if (drv)
> + drv->states[1].target_residency = residency;
> +}
> +
> +static int powerpc_cpuidle_add_cpu_notifier(struct notifier_block *n,
> + unsigned long action, void *hcpu)
> +{
> + int hotcpu = (unsigned long)hcpu;
> + struct cpuidle_device *dev =
> + per_cpu_ptr(cpuidle_devices, hotcpu);
> +
> + if (dev && cpuidle_get_driver()) {
> + switch (action) {
> + case CPU_ONLINE:
> + case CPU_ONLINE_FROZEN:
> + cpuidle_pause_and_lock();
> + cpuidle_enable_device(dev);
> + cpuidle_resume_and_unlock();
> + break;
> +
> + case CPU_DEAD:
> + case CPU_DEAD_FROZEN:
> + cpuidle_pause_and_lock();
> + cpuidle_disable_device(dev);
> + cpuidle_resume_and_unlock();
> + break;
> +
> + default:
> + return NOTIFY_DONE;
> + }
> + }
> + return NOTIFY_OK;
> +}
> +
> +static struct notifier_block setup_hotplug_notifier = {
> + .notifier_call = powerpc_cpuidle_add_cpu_notifier,
> +};
> +
> +/*
> + * powerpc_cpuidle_driver_init()
> + */
> +static int powerpc_cpuidle_driver_init(void)
> +{
> + int idle_state;
> + struct cpuidle_driver *drv = &powerpc_idle_driver;
> +
> + drv->state_count = 0;
> +
> + for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
> +
> + if (idle_state > max_idle_state)
> + break;
> +
> + /* is the state not enabled? */
> + if (cpuidle_state_table[idle_state].enter == NULL)
> + continue;
> +
> + drv->states[drv->state_count] = /* structure copy */
> + cpuidle_state_table[idle_state];
> +
> + drv->state_count += 1;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * powerpc_idle_probe()
> + * Choose state table for shared versus dedicated partition
> + */
> +static int powerpc_idle_probe(void)
> +{
> +
> + if (cpuidle_disable != IDLE_NO_OVERRIDE)
> + return -ENODEV;
> +
> + if (max_idle_state == 0) {
> + printk(KERN_DEBUG "powerpc processor idle disabled.\n");
> + return -EPERM;
> + }
> +
> + if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
> + if (get_lppaca_is_shared_proc() == 1)
> + cpuidle_state_table = shared_states;
> + else if (get_lppaca_is_shared_proc() == 0)
> + cpuidle_state_table = dedicated_states;
> + } else
> + return -ENODEV;
> +
> + return 0;
> +}
> +
> +static int __init powerpc_processor_idle_init(void)
> +{
> + int retval;
> +
> + retval = powerpc_idle_probe();
> + if (retval)
> + return retval;
> +
> + powerpc_cpuidle_driver_init();
> + retval = cpuidle_register(&powerpc_idle_driver, NULL);
> + if (retval) {
> + printk(KERN_DEBUG "Registration of powerpc driver failed.\n");
> + return retval;
> + }
> +
> + register_cpu_notifier(&setup_hotplug_notifier);
> + printk(KERN_DEBUG "powerpc_idle_driver registered\n");
> +
> + return 0;
> +}
> +
> +static void __exit powerpc_processor_idle_exit(void)
> +{
> +
> + unregister_cpu_notifier(&setup_hotplug_notifier);
> + cpuidle_unregister(&powerpc_idle_driver);
> + return;
> +}
> +
> +module_init(powerpc_processor_idle_init);
> +module_exit(powerpc_processor_idle_exit);
> +
> +MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
> +MODULE_DESCRIPTION("Cpuidle driver for powerpc");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH v4 01/31] spi: mpc512x: cleanup clock API use
From: Mark Brown @ 2013-08-22 10:02 UTC (permalink / raw)
To: Gerhard Sittig
Cc: devicetree, Mike Turquette, Detlev Zundel, Wolfram Sang,
David Woodhouse, Greg Kroah-Hartman, Rob Herring,
Marc Kleine-Budde, Wolfgang Grandegger, Anatolij Gustschin,
linuxppc-dev, linux-arm-kernel, Mauro Carvalho Chehab
In-Reply-To: <1375821851-31609-2-git-send-email-gsi@denx.de>
[-- Attachment #1: Type: text/plain, Size: 306 bytes --]
On Tue, Aug 06, 2013 at 10:43:41PM +0200, Gerhard Sittig wrote:
> cleanup the MPC512x SoC's SPI master's use of the clock API
> - get, prepare, and enable the MCLK during probe; disable, unprepare and
> put the MCLK upon remove; hold a reference to the clock over the
> period of use
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH V5 5/5] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
From: Deepthi Dharwar @ 2013-08-22 9:54 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
In-Reply-To: <20130822095323.27416.79369.stgit@deepthi.in.ibm.com>
This patch enables idle cpu on the powernv platform to hook on to the cpuidle
framework, if available, else call on to default idle platform
code.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
arch/powerpc/platforms/powernv/setup.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 84438af..fc62f21 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -25,6 +25,7 @@
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/bug.h>
+#include <linux/cpuidle.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
@@ -175,6 +176,17 @@ static void __init pnv_setup_machdep_rtas(void)
}
#endif /* CONFIG_PPC_POWERNV_RTAS */
+void powernv_idle(void)
+{
+ /* Hook to cpuidle framework if available, else
+ * call on default platform idle code
+ */
+ if (cpuidle_idle_call()) {
+ HMT_low();
+ HMT_very_low();
+ }
+}
+
static int __init pnv_probe(void)
{
unsigned long root = of_get_flat_dt_root();
@@ -205,7 +217,7 @@ define_machine(powernv) {
.show_cpuinfo = pnv_show_cpuinfo,
.progress = pnv_progress,
.machine_shutdown = pnv_shutdown,
- .power_save = power7_idle,
+ .power_save = powernv_idle,
.calibrate_decr = generic_calibrate_decr,
#ifdef CONFIG_KEXEC
.kexec_cpu_down = pnv_kexec_cpu_down,
^ permalink raw reply related
* [PATCH V5 4/5] POWER/cpuidle: Enable powernv cpuidle support.
From: Deepthi Dharwar @ 2013-08-22 9:54 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
In-Reply-To: <20130822095323.27416.79369.stgit@deepthi.in.ibm.com>
The following patch extends the current power backend
idle driver to the powernv platform.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle-ibm-power.c | 37 ++++++++++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 3 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index 4ee5a94..de5e837 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -50,9 +50,11 @@ static int snooze_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- unsigned long in_purr;
+ unsigned long in_purr = 0;
+
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
+ idle_loop_prolog(&in_purr);
- idle_loop_prolog(&in_purr);
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
@@ -66,7 +68,8 @@ static int snooze_loop(struct cpuidle_device *dev,
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb();
- idle_loop_epilog(in_purr);
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
+ idle_loop_epilog(in_purr);
return index;
}
@@ -129,6 +132,15 @@ static int shared_cede_loop(struct cpuidle_device *dev,
return index;
}
+static int nap_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ ppc64_runlatch_off();
+ power7_idle();
+ return index;
+}
+
/*
* States for dedicated partition case.
*/
@@ -162,6 +174,23 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
.enter = &shared_cede_loop },
};
+static struct cpuidle_state powernv_states[MAX_IDLE_STATE_COUNT] = {
+ { /* Snooze */
+ .name = "snooze",
+ .desc = "snooze",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 0,
+ .target_residency = 0,
+ .enter = &snooze_loop },
+ { /* NAP */
+ .name = "NAP",
+ .desc = "NAP",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 100,
+ .enter = &nap_loop },
+};
+
void update_smt_snooze_delay(int cpu, int residency)
{
struct cpuidle_driver *drv = cpuidle_get_driver();
@@ -261,6 +290,8 @@ static int power_idle_probe(void)
cpuidle_state_table = shared_states;
else
cpuidle_state_table = dedicated_states;
+ } else if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+ cpuidle_state_table = powernv_states;
} else
return -ENODEV;
^ permalink raw reply related
* [PATCH V5 3/5] POWER/cpuidle: Generic IBM-POWER backend cpuidle driver.
From: Deepthi Dharwar @ 2013-08-22 9:54 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
In-Reply-To: <20130822095323.27416.79369.stgit@deepthi.in.ibm.com>
This patch involves moving the current pseries_idle backend driver code
from pseries/processor_idle.c to drivers/cpuidle/cpuidle-ibm-power.c.
It enables the support for pseries platform, such that going forward the
same code with minimal efforts can be re-used for a common driver on powernv
This removes a lot of code duplicacy, thus making the code elegant.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/processor.h | 2
arch/powerpc/platforms/pseries/Kconfig | 9 -
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/processor_idle.c | 360 -----------------------
drivers/cpuidle/Kconfig | 7
drivers/cpuidle/Makefile | 2
drivers/cpuidle/cpuidle-ibm-power.c | 304 +++++++++++++++++++
7 files changed, 314 insertions(+), 371 deletions(-)
delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
create mode 100644 drivers/cpuidle/cpuidle-ibm-power.c
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index e378ccc..ab444ff 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -430,7 +430,7 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
extern int powersave_nap; /* set if nap mode can be used in idle loop */
extern void power7_nap(void);
-#ifdef CONFIG_PSERIES_IDLE
+#ifdef CONFIG_CPU_IDLE_IBM_POWER
extern void update_smt_snooze_delay(int cpu, int residency);
#else
static inline void update_smt_snooze_delay(int cpu, int residency) {}
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 62b4f80..bb59bb0 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -119,12 +119,3 @@ config DTL
which are accessible through a debugfs file.
Say N if you are unsure.
-
-config PSERIES_IDLE
- bool "Cpuidle driver for pSeries platforms"
- depends on CPU_IDLE
- depends on PPC_PSERIES
- default y
- help
- Select this option to enable processor idle state management
- through cpuidle subsystem.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 8ae0103..4b22379 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_DTL) += dtl.o
obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
-obj-$(CONFIG_PSERIES_IDLE) += processor_idle.o
ifeq ($(CONFIG_PPC_PSERIES),y)
obj-$(CONFIG_SUSPEND) += suspend.o
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
deleted file mode 100644
index c905b99..0000000
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * processor_idle - idle state cpuidle driver.
- * Adapted from drivers/idle/intel_idle.c and
- * drivers/acpi/processor_idle.c
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-#include <linux/cpuidle.h>
-#include <linux/cpu.h>
-#include <linux/notifier.h>
-
-#include <asm/paca.h>
-#include <asm/reg.h>
-#include <asm/machdep.h>
-#include <asm/firmware.h>
-#include <asm/runlatch.h>
-#include <asm/plpar_wrappers.h>
-
-struct cpuidle_driver pseries_idle_driver = {
- .name = "pseries_idle",
- .owner = THIS_MODULE,
-};
-
-#define MAX_IDLE_STATE_COUNT 2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
-static struct cpuidle_device __percpu *pseries_cpuidle_devices;
-static struct cpuidle_state *cpuidle_state_table;
-
-static inline void idle_loop_prolog(unsigned long *in_purr)
-{
- *in_purr = mfspr(SPRN_PURR);
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- get_lppaca()->idle = 1;
-}
-
-static inline void idle_loop_epilog(unsigned long in_purr)
-{
- get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
- get_lppaca()->idle = 0;
-}
-
-static int snooze_loop(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
-{
- unsigned long in_purr;
- int cpu = dev->cpu;
-
- idle_loop_prolog(&in_purr);
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while ((!need_resched()) && cpu_online(cpu)) {
- ppc64_runlatch_off();
- HMT_low();
- HMT_very_low();
- }
-
- HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb();
-
- idle_loop_epilog(in_purr);
-
- return index;
-}
-
-static void check_and_cede_processor(void)
-{
- /*
- * Ensure our interrupt state is properly tracked,
- * also checks if no interrupt has occurred while we
- * were soft-disabled
- */
- if (prep_irq_for_idle()) {
- cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
- /* Ensure that H_CEDE returns with IRQs on */
- if (WARN_ON(!(mfmsr() & MSR_EE)))
- __hard_irq_enable();
-#endif
- }
-}
-
-static int dedicated_cede_loop(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
-{
- unsigned long in_purr;
-
- idle_loop_prolog(&in_purr);
- get_lppaca()->donate_dedicated_cpu = 1;
-
- ppc64_runlatch_off();
- HMT_medium();
- check_and_cede_processor();
-
- get_lppaca()->donate_dedicated_cpu = 0;
-
- idle_loop_epilog(in_purr);
-
- return index;
-}
-
-static int shared_cede_loop(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
-{
- unsigned long in_purr;
-
- idle_loop_prolog(&in_purr);
-
- /*
- * Yield the processor to the hypervisor. We return if
- * an external interrupt occurs (which are driven prior
- * to returning here) or if a prod occurs from another
- * processor. When returning here, external interrupts
- * are enabled.
- */
- check_and_cede_processor();
-
- idle_loop_epilog(in_purr);
-
- return index;
-}
-
-/*
- * States for dedicated partition case.
- */
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
- { /* Snooze */
- .name = "snooze",
- .desc = "snooze",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 0,
- .target_residency = 0,
- .enter = &snooze_loop },
- { /* CEDE */
- .name = "CEDE",
- .desc = "CEDE",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 10,
- .target_residency = 100,
- .enter = &dedicated_cede_loop },
-};
-
-/*
- * States for shared partition case.
- */
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
- { /* Shared Cede */
- .name = "Shared Cede",
- .desc = "Shared Cede",
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .exit_latency = 0,
- .target_residency = 0,
- .enter = &shared_cede_loop },
-};
-
-void update_smt_snooze_delay(int cpu, int residency)
-{
- struct cpuidle_driver *drv = cpuidle_get_driver();
- struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
-
- if (cpuidle_state_table != dedicated_states)
- return;
-
- if (residency < 0) {
- /* Disable the Nap state on that cpu */
- if (dev)
- dev->states_usage[1].disable = 1;
- } else
- if (drv)
- drv->states[1].target_residency = residency;
-}
-
-static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
- unsigned long action, void *hcpu)
-{
- int hotcpu = (unsigned long)hcpu;
- struct cpuidle_device *dev =
- per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
-
- if (dev && cpuidle_get_driver()) {
- switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpuidle_pause_and_lock();
- cpuidle_enable_device(dev);
- cpuidle_resume_and_unlock();
- break;
-
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- cpuidle_pause_and_lock();
- cpuidle_disable_device(dev);
- cpuidle_resume_and_unlock();
- break;
-
- default:
- return NOTIFY_DONE;
- }
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block setup_hotplug_notifier = {
- .notifier_call = pseries_cpuidle_add_cpu_notifier,
-};
-
-/*
- * pseries_cpuidle_driver_init()
- */
-static int pseries_cpuidle_driver_init(void)
-{
- int idle_state;
- struct cpuidle_driver *drv = &pseries_idle_driver;
-
- drv->state_count = 0;
-
- for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
-
- if (idle_state > max_idle_state)
- break;
-
- /* is the state not enabled? */
- if (cpuidle_state_table[idle_state].enter == NULL)
- continue;
-
- drv->states[drv->state_count] = /* structure copy */
- cpuidle_state_table[idle_state];
-
- drv->state_count += 1;
- }
-
- return 0;
-}
-
-/* pseries_idle_devices_uninit(void)
- * unregister cpuidle devices and de-allocate memory
- */
-static void pseries_idle_devices_uninit(void)
-{
- int i;
- struct cpuidle_device *dev;
-
- for_each_possible_cpu(i) {
- dev = per_cpu_ptr(pseries_cpuidle_devices, i);
- cpuidle_unregister_device(dev);
- }
-
- free_percpu(pseries_cpuidle_devices);
- return;
-}
-
-/* pseries_idle_devices_init()
- * allocate, initialize and register cpuidle device
- */
-static int pseries_idle_devices_init(void)
-{
- int i;
- struct cpuidle_driver *drv = &pseries_idle_driver;
- struct cpuidle_device *dev;
-
- pseries_cpuidle_devices = alloc_percpu(struct cpuidle_device);
- if (pseries_cpuidle_devices == NULL)
- return -ENOMEM;
-
- for_each_possible_cpu(i) {
- dev = per_cpu_ptr(pseries_cpuidle_devices, i);
- dev->state_count = drv->state_count;
- dev->cpu = i;
- if (cpuidle_register_device(dev)) {
- printk(KERN_DEBUG \
- "cpuidle_register_device %d failed!\n", i);
- return -EIO;
- }
- }
-
- return 0;
-}
-
-/*
- * pseries_idle_probe()
- * Choose state table for shared versus dedicated partition
- */
-static int pseries_idle_probe(void)
-{
-
- if (!firmware_has_feature(FW_FEATURE_SPLPAR))
- return -ENODEV;
-
- if (cpuidle_disable != IDLE_NO_OVERRIDE)
- return -ENODEV;
-
- if (max_idle_state == 0) {
- printk(KERN_DEBUG "pseries processor idle disabled.\n");
- return -EPERM;
- }
-
- if (get_lppaca()->shared_proc)
- cpuidle_state_table = shared_states;
- else
- cpuidle_state_table = dedicated_states;
-
- return 0;
-}
-
-static int __init pseries_processor_idle_init(void)
-{
- int retval;
-
- retval = pseries_idle_probe();
- if (retval)
- return retval;
-
- pseries_cpuidle_driver_init();
- retval = cpuidle_register_driver(&pseries_idle_driver);
- if (retval) {
- printk(KERN_DEBUG "Registration of pseries driver failed.\n");
- return retval;
- }
-
- retval = pseries_idle_devices_init();
- if (retval) {
- pseries_idle_devices_uninit();
- cpuidle_unregister_driver(&pseries_idle_driver);
- return retval;
- }
-
- register_cpu_notifier(&setup_hotplug_notifier);
- printk(KERN_DEBUG "pseries_idle_driver registered\n");
-
- return 0;
-}
-
-static void __exit pseries_processor_idle_exit(void)
-{
-
- unregister_cpu_notifier(&setup_hotplug_notifier);
- pseries_idle_devices_uninit();
- cpuidle_unregister_driver(&pseries_idle_driver);
-
- return;
-}
-
-module_init(pseries_processor_idle_init);
-module_exit(pseries_processor_idle_exit);
-
-MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("Cpuidle driver for POWER");
-MODULE_LICENSE("GPL");
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 0e2cd5c..e805dcd 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -42,6 +42,13 @@ config CPU_IDLE_ZYNQ
help
Select this to enable cpuidle on Xilinx Zynq processors.
+config CPU_IDLE_IBM_POWER
+ bool "CPU Idle driver for IBM POWER platforms"
+ depends on PPC_PSERIES || PPC_POWERNV
+ default y
+ help
+ Select this option to enable processor idle state management
+ on IBM POWER platform.
endif
config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 8767a7b..b6c8092 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -8,3 +8,5 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
+
+obj-$(CONFIG_CPU_IDLE_IBM_POWER) += cpuidle-ibm-power.o
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
new file mode 100644
index 0000000..4ee5a94
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -0,0 +1,304 @@
+/*
+ * cpuidle-ibm-power - idle state cpuidle driver.
+ * Adapted from drivers/idle/intel_idle.c and
+ * drivers/acpi/processor_idle.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+
+#include <asm/paca.h>
+#include <asm/reg.h>
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+#include <asm/runlatch.h>
+#include <asm/plpar_wrappers.h>
+
+struct cpuidle_driver power_idle_driver = {
+ .name = "IBM-POWER-Idle",
+ .owner = THIS_MODULE,
+};
+
+#define MAX_IDLE_STATE_COUNT 2
+
+static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static struct cpuidle_state *cpuidle_state_table;
+
+static inline void idle_loop_prolog(unsigned long *in_purr)
+{
+ *in_purr = mfspr(SPRN_PURR);
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ get_lppaca()->idle = 1;
+}
+
+static inline void idle_loop_epilog(unsigned long in_purr)
+{
+ get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
+ get_lppaca()->idle = 0;
+}
+
+static int snooze_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+
+ idle_loop_prolog(&in_purr);
+ local_irq_enable();
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ while (!need_resched()) {
+ ppc64_runlatch_off();
+ HMT_low();
+ HMT_very_low();
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ smp_mb();
+
+ idle_loop_epilog(in_purr);
+
+ return index;
+}
+
+static void check_and_cede_processor(void)
+{
+ /*
+ * Ensure our interrupt state is properly tracked,
+ * also checks if no interrupt has occurred while we
+ * were soft-disabled
+ */
+ if (prep_irq_for_idle()) {
+ cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
+#endif
+ }
+}
+
+static int dedicated_cede_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+
+ idle_loop_prolog(&in_purr);
+ get_lppaca()->donate_dedicated_cpu = 1;
+
+ ppc64_runlatch_off();
+ HMT_medium();
+ check_and_cede_processor();
+
+ get_lppaca()->donate_dedicated_cpu = 0;
+ idle_loop_epilog(in_purr);
+
+ return index;
+}
+
+static int shared_cede_loop(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ unsigned long in_purr;
+
+ idle_loop_prolog(&in_purr);
+
+ /*
+ * Yield the processor to the hypervisor. We return if
+ * an external interrupt occurs (which are driven prior
+ * to returning here) or if a prod occurs from another
+ * processor. When returning here, external interrupts
+ * are enabled.
+ */
+ check_and_cede_processor();
+
+ idle_loop_epilog(in_purr);
+
+ return index;
+}
+
+/*
+ * States for dedicated partition case.
+ */
+static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+ { /* Snooze */
+ .name = "snooze",
+ .desc = "snooze",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 0,
+ .target_residency = 0,
+ .enter = &snooze_loop },
+ { /* CEDE */
+ .name = "CEDE",
+ .desc = "CEDE",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 10,
+ .target_residency = 100,
+ .enter = &dedicated_cede_loop },
+};
+
+/*
+ * States for shared partition case.
+ */
+static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+ { /* Shared Cede */
+ .name = "Shared Cede",
+ .desc = "Shared Cede",
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .exit_latency = 0,
+ .target_residency = 0,
+ .enter = &shared_cede_loop },
+};
+
+void update_smt_snooze_delay(int cpu, int residency)
+{
+ struct cpuidle_driver *drv = cpuidle_get_driver();
+ struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
+
+ if (cpuidle_state_table != dedicated_states)
+ return;
+
+ if (residency < 0) {
+ /* Disable the Nap state on that cpu */
+ if (dev)
+ dev->states_usage[1].disable = 1;
+ } else
+ if (drv)
+ drv->states[1].target_residency = residency;
+}
+
+static int power_cpuidle_add_cpu_notifier(struct notifier_block *n,
+ unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+ struct cpuidle_device *dev =
+ per_cpu_ptr(cpuidle_devices, hotcpu);
+
+ if (dev && cpuidle_get_driver()) {
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ cpuidle_pause_and_lock();
+ cpuidle_enable_device(dev);
+ cpuidle_resume_and_unlock();
+ break;
+
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ cpuidle_pause_and_lock();
+ cpuidle_disable_device(dev);
+ cpuidle_resume_and_unlock();
+ break;
+
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block setup_hotplug_notifier = {
+ .notifier_call = power_cpuidle_add_cpu_notifier,
+};
+
+/*
+ * power_cpuidle_driver_init()
+ */
+static int power_cpuidle_driver_init(void)
+{
+ int idle_state;
+ struct cpuidle_driver *drv = &power_idle_driver;
+
+ drv->state_count = 0;
+
+ for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
+
+ if (idle_state > max_idle_state)
+ break;
+
+ /* is the state not enabled? */
+ if (cpuidle_state_table[idle_state].enter == NULL)
+ continue;
+
+ drv->states[drv->state_count] = /* structure copy */
+ cpuidle_state_table[idle_state];
+
+ drv->state_count += 1;
+ }
+
+ return 0;
+}
+
+/*
+ * power_idle_probe()
+ * Choose state table for shared versus dedicated partition
+ */
+static int power_idle_probe(void)
+{
+
+ if (cpuidle_disable != IDLE_NO_OVERRIDE)
+ return -ENODEV;
+
+ if (max_idle_state == 0) {
+ printk(KERN_DEBUG "power processor idle disabled.\n");
+ return -EPERM;
+ }
+
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ if (get_lppaca()->shared_proc)
+ cpuidle_state_table = shared_states;
+ else
+ cpuidle_state_table = dedicated_states;
+ } else
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __init power_processor_idle_init(void)
+{
+ int retval;
+
+ retval = power_idle_probe();
+ if (retval)
+ return retval;
+
+ power_cpuidle_driver_init();
+ retval = cpuidle_register(&power_idle_driver, NULL);
+ if (retval) {
+ printk(KERN_DEBUG "Registration of power idle driver failed.\n");
+ return retval;
+ }
+
+ register_cpu_notifier(&setup_hotplug_notifier);
+ printk(KERN_DEBUG "power_idle_driver registered\n");
+
+ return 0;
+}
+
+static void __exit power_processor_idle_exit(void)
+{
+
+ unregister_cpu_notifier(&setup_hotplug_notifier);
+ cpuidle_unregister(&power_idle_driver);
+ return;
+}
+
+module_init(power_processor_idle_init);
+module_exit(power_processor_idle_exit);
+
+MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("Cpuidle driver for IBM POWER platforms");
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* [PATCH V5 2/5] pseries: Move plpar_wrapper.h to powerpc common include/asm location.
From: Deepthi Dharwar @ 2013-08-22 9:53 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
In-Reply-To: <20130822095323.27416.79369.stgit@deepthi.in.ibm.com>
As a part of pseries_idle backend driver cleanup to make
the code common to both pseries and powernv platforms, it
is necessary to move the backend-driver code to drivers/cpuidle.
As a pre-requisite for that, it is essential to move plpar_wrapper.h
to include/asm.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/plpar_wrappers.h | 325 +++++++++++++++++++++++
arch/powerpc/platforms/pseries/cmm.c | 3
arch/powerpc/platforms/pseries/dtl.c | 3
arch/powerpc/platforms/pseries/hotplug-cpu.c | 3
arch/powerpc/platforms/pseries/hvconsole.c | 2
arch/powerpc/platforms/pseries/iommu.c | 3
arch/powerpc/platforms/pseries/kexec.c | 2
arch/powerpc/platforms/pseries/lpar.c | 2
arch/powerpc/platforms/pseries/plpar_wrappers.h | 324 -----------------------
arch/powerpc/platforms/pseries/processor_idle.c | 3
arch/powerpc/platforms/pseries/setup.c | 2
arch/powerpc/platforms/pseries/smp.c | 2
12 files changed, 336 insertions(+), 338 deletions(-)
create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h
delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h
diff --git a/arch/powerpc/include/asm/plpar_wrappers.h b/arch/powerpc/include/asm/plpar_wrappers.h
new file mode 100644
index 0000000..e2f84d6
--- /dev/null
+++ b/arch/powerpc/include/asm/plpar_wrappers.h
@@ -0,0 +1,325 @@
+#ifndef _PSERIES_PLPAR_WRAPPERS_H
+#define _PSERIES_PLPAR_WRAPPERS_H
+
+#include <linux/string.h>
+#include <linux/irqflags.h>
+
+#include <asm/hvcall.h>
+#include <asm/paca.h>
+#include <asm/page.h>
+
+/* Get state of physical CPU from query_cpu_stopped */
+int smp_query_cpu_stopped(unsigned int pcpu);
+#define QCSS_STOPPED 0
+#define QCSS_STOPPING 1
+#define QCSS_NOT_STOPPED 2
+#define QCSS_HARDWARE_ERROR -1
+#define QCSS_HARDWARE_BUSY -2
+
+static inline long poll_pending(void)
+{
+ return plpar_hcall_norets(H_POLL_PENDING);
+}
+
+static inline u8 get_cede_latency_hint(void)
+{
+ return get_lppaca()->cede_latency_hint;
+}
+
+static inline void set_cede_latency_hint(u8 latency_hint)
+{
+ get_lppaca()->cede_latency_hint = latency_hint;
+}
+
+static inline long cede_processor(void)
+{
+ return plpar_hcall_norets(H_CEDE);
+}
+
+static inline long extended_cede_processor(unsigned long latency_hint)
+{
+ long rc;
+ u8 old_latency_hint = get_cede_latency_hint();
+
+ set_cede_latency_hint(latency_hint);
+
+ rc = cede_processor();
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Ensure that H_CEDE returns with IRQs on */
+ if (WARN_ON(!(mfmsr() & MSR_EE)))
+ __hard_irq_enable();
+#endif
+
+ set_cede_latency_hint(old_latency_hint);
+
+ return rc;
+}
+
+static inline long vpa_call(unsigned long flags, unsigned long cpu,
+ unsigned long vpa)
+{
+ flags = flags << H_VPA_FUNC_SHIFT;
+
+ return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
+}
+
+static inline long unregister_vpa(unsigned long cpu)
+{
+ return vpa_call(H_VPA_DEREG_VPA, cpu, 0);
+}
+
+static inline long register_vpa(unsigned long cpu, unsigned long vpa)
+{
+ return vpa_call(H_VPA_REG_VPA, cpu, vpa);
+}
+
+static inline long unregister_slb_shadow(unsigned long cpu)
+{
+ return vpa_call(H_VPA_DEREG_SLB, cpu, 0);
+}
+
+static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
+{
+ return vpa_call(H_VPA_REG_SLB, cpu, vpa);
+}
+
+static inline long unregister_dtl(unsigned long cpu)
+{
+ return vpa_call(H_VPA_DEREG_DTL, cpu, 0);
+}
+
+static inline long register_dtl(unsigned long cpu, unsigned long vpa)
+{
+ return vpa_call(H_VPA_REG_DTL, cpu, vpa);
+}
+
+static inline long plpar_page_set_loaned(unsigned long vpa)
+{
+ unsigned long cmo_page_sz = cmo_get_page_size();
+ long rc = 0;
+ int i;
+
+ for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
+ rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0);
+
+ for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
+ plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE,
+ vpa + i - cmo_page_sz, 0);
+
+ return rc;
+}
+
+static inline long plpar_page_set_active(unsigned long vpa)
+{
+ unsigned long cmo_page_sz = cmo_get_page_size();
+ long rc = 0;
+ int i;
+
+ for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
+ rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0);
+
+ for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
+ plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED,
+ vpa + i - cmo_page_sz, 0);
+
+ return rc;
+}
+
+extern void vpa_init(int cpu);
+
+static inline long plpar_pte_enter(unsigned long flags,
+ unsigned long hpte_group, unsigned long hpte_v,
+ unsigned long hpte_r, unsigned long *slot)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
+
+ *slot = retbuf[0];
+
+ return rc;
+}
+
+static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
+ unsigned long avpn, unsigned long *old_pteh_ret,
+ unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
+/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
+ unsigned long avpn, unsigned long *old_pteh_ret,
+ unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
+static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
+ unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_READ, retbuf, flags, ptex);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
+/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
+ unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
+/*
+ * plpar_pte_read_4_raw can be called in real mode.
+ * ptes must be 8*sizeof(unsigned long)
+ */
+static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
+ unsigned long *ptes)
+
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
+
+ memcpy(ptes, retbuf, 8*sizeof(unsigned long));
+
+ return rc;
+}
+
+static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
+ unsigned long avpn)
+{
+ return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
+}
+
+static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
+ unsigned long *tce_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
+
+ *tce_ret = retbuf[0];
+
+ return rc;
+}
+
+static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
+ unsigned long tceval)
+{
+ return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
+}
+
+static inline long plpar_tce_put_indirect(unsigned long liobn,
+ unsigned long ioba, unsigned long page, unsigned long count)
+{
+ return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
+}
+
+static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba,
+ unsigned long tceval, unsigned long count)
+{
+ return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
+}
+
+static inline long plpar_get_term_char(unsigned long termno,
+ unsigned long *len_ret, char *buf_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */
+
+ rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
+
+ *len_ret = retbuf[0];
+ lbuf[0] = retbuf[1];
+ lbuf[1] = retbuf[2];
+
+ return rc;
+}
+
+static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
+ const char *buffer)
+{
+ unsigned long *lbuf = (unsigned long *)buffer; /* TODO: alignment? */
+ return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
+ lbuf[1]);
+}
+
+/* Set various resource mode parameters */
+static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
+ unsigned long value1, unsigned long value2)
+{
+ return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
+}
+
+/*
+ * Enable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long enable_reloc_on_exceptions(void)
+{
+ /* mflags = 3: Exceptions at 0xC000000000004000 */
+ return plpar_set_mode(3, 3, 0, 0);
+}
+
+/*
+ * Disable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long disable_reloc_on_exceptions(void)
+{
+ return plpar_set_mode(0, 3, 0, 0);
+}
+
+static inline long plapr_set_ciabr(unsigned long ciabr)
+{
+ return plpar_set_mode(0, 1, ciabr, 0);
+}
+
+static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
+{
+ return plpar_set_mode(0, 2, dawr0, dawrx0);
+}
+
+#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index c638535..1e561be 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -40,8 +40,7 @@
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <linux/memory.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
#define CMM_DRIVER_VERSION "1.0.0"
#define CMM_DEFAULT_DELAY 1
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index 0cc0ac0..f6cb051 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -29,8 +29,7 @@
#include <asm/firmware.h>
#include <asm/lppaca.h>
#include <asm/debug.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
struct dtl {
struct dtl_entry *buf;
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 217ca5c..a8ef932 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -30,7 +30,8 @@
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
#include <asm/xics.h>
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
+
#include "offline_states.h"
/* This version can't take the spinlock, because it never returns */
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index b344f94..f3f108b 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -28,7 +28,7 @@
#include <linux/errno.h>
#include <asm/hvcall.h>
#include <asm/hvconsole.h>
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
/**
* hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 23fc1dc..4821933 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -48,8 +48,7 @@
#include <asm/ppc-pci.h>
#include <asm/udbg.h>
#include <asm/mmzone.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
static void tce_invalidate_pSeries_sw(struct iommu_table *tbl,
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index 7d94bdc..13fa95b3 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -17,9 +17,9 @@
#include <asm/mpic.h>
#include <asm/xics.h>
#include <asm/smp.h>
+#include <asm/plpar_wrappers.h>
#include "pseries.h"
-#include "plpar_wrappers.h"
static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
{
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 8bad880..e1873bc 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -41,8 +41,8 @@
#include <asm/smp.h>
#include <asm/trace.h>
#include <asm/firmware.h>
+#include <asm/plpar_wrappers.h>
-#include "plpar_wrappers.h"
#include "pseries.h"
/* Flag bits for H_BULK_REMOVE */
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
deleted file mode 100644
index f35787b..0000000
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef _PSERIES_PLPAR_WRAPPERS_H
-#define _PSERIES_PLPAR_WRAPPERS_H
-
-#include <linux/string.h>
-#include <linux/irqflags.h>
-
-#include <asm/hvcall.h>
-#include <asm/paca.h>
-#include <asm/page.h>
-
-/* Get state of physical CPU from query_cpu_stopped */
-int smp_query_cpu_stopped(unsigned int pcpu);
-#define QCSS_STOPPED 0
-#define QCSS_STOPPING 1
-#define QCSS_NOT_STOPPED 2
-#define QCSS_HARDWARE_ERROR -1
-#define QCSS_HARDWARE_BUSY -2
-
-static inline long poll_pending(void)
-{
- return plpar_hcall_norets(H_POLL_PENDING);
-}
-
-static inline u8 get_cede_latency_hint(void)
-{
- return get_lppaca()->cede_latency_hint;
-}
-
-static inline void set_cede_latency_hint(u8 latency_hint)
-{
- get_lppaca()->cede_latency_hint = latency_hint;
-}
-
-static inline long cede_processor(void)
-{
- return plpar_hcall_norets(H_CEDE);
-}
-
-static inline long extended_cede_processor(unsigned long latency_hint)
-{
- long rc;
- u8 old_latency_hint = get_cede_latency_hint();
-
- set_cede_latency_hint(latency_hint);
-
- rc = cede_processor();
-#ifdef CONFIG_TRACE_IRQFLAGS
- /* Ensure that H_CEDE returns with IRQs on */
- if (WARN_ON(!(mfmsr() & MSR_EE)))
- __hard_irq_enable();
-#endif
-
- set_cede_latency_hint(old_latency_hint);
-
- return rc;
-}
-
-static inline long vpa_call(unsigned long flags, unsigned long cpu,
- unsigned long vpa)
-{
- flags = flags << H_VPA_FUNC_SHIFT;
-
- return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
-}
-
-static inline long unregister_vpa(unsigned long cpu)
-{
- return vpa_call(H_VPA_DEREG_VPA, cpu, 0);
-}
-
-static inline long register_vpa(unsigned long cpu, unsigned long vpa)
-{
- return vpa_call(H_VPA_REG_VPA, cpu, vpa);
-}
-
-static inline long unregister_slb_shadow(unsigned long cpu)
-{
- return vpa_call(H_VPA_DEREG_SLB, cpu, 0);
-}
-
-static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
-{
- return vpa_call(H_VPA_REG_SLB, cpu, vpa);
-}
-
-static inline long unregister_dtl(unsigned long cpu)
-{
- return vpa_call(H_VPA_DEREG_DTL, cpu, 0);
-}
-
-static inline long register_dtl(unsigned long cpu, unsigned long vpa)
-{
- return vpa_call(H_VPA_REG_DTL, cpu, vpa);
-}
-
-static inline long plpar_page_set_loaned(unsigned long vpa)
-{
- unsigned long cmo_page_sz = cmo_get_page_size();
- long rc = 0;
- int i;
-
- for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
- rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED, vpa + i, 0);
-
- for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
- plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE,
- vpa + i - cmo_page_sz, 0);
-
- return rc;
-}
-
-static inline long plpar_page_set_active(unsigned long vpa)
-{
- unsigned long cmo_page_sz = cmo_get_page_size();
- long rc = 0;
- int i;
-
- for (i = 0; !rc && i < PAGE_SIZE; i += cmo_page_sz)
- rc = plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_ACTIVE, vpa + i, 0);
-
- for (i -= cmo_page_sz; rc && i != 0; i -= cmo_page_sz)
- plpar_hcall_norets(H_PAGE_INIT, H_PAGE_SET_LOANED,
- vpa + i - cmo_page_sz, 0);
-
- return rc;
-}
-
-extern void vpa_init(int cpu);
-
-static inline long plpar_pte_enter(unsigned long flags,
- unsigned long hpte_group, unsigned long hpte_v,
- unsigned long hpte_r, unsigned long *slot)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
-
- *slot = retbuf[0];
-
- return rc;
-}
-
-static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
- unsigned long avpn, unsigned long *old_pteh_ret,
- unsigned long *old_ptel_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
-
- *old_pteh_ret = retbuf[0];
- *old_ptel_ret = retbuf[1];
-
- return rc;
-}
-
-/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
-static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
- unsigned long avpn, unsigned long *old_pteh_ret,
- unsigned long *old_ptel_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
-
- *old_pteh_ret = retbuf[0];
- *old_ptel_ret = retbuf[1];
-
- return rc;
-}
-
-static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
- unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_READ, retbuf, flags, ptex);
-
- *old_pteh_ret = retbuf[0];
- *old_ptel_ret = retbuf[1];
-
- return rc;
-}
-
-/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
-static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
- unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
-
- *old_pteh_ret = retbuf[0];
- *old_ptel_ret = retbuf[1];
-
- return rc;
-}
-
-/*
- * plpar_pte_read_4_raw can be called in real mode.
- * ptes must be 8*sizeof(unsigned long)
- */
-static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
- unsigned long *ptes)
-
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
-
- rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
-
- memcpy(ptes, retbuf, 8*sizeof(unsigned long));
-
- return rc;
-}
-
-static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
- unsigned long avpn)
-{
- return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
-}
-
-static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
- unsigned long *tce_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
-
- *tce_ret = retbuf[0];
-
- return rc;
-}
-
-static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
- unsigned long tceval)
-{
- return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
-}
-
-static inline long plpar_tce_put_indirect(unsigned long liobn,
- unsigned long ioba, unsigned long page, unsigned long count)
-{
- return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
-}
-
-static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba,
- unsigned long tceval, unsigned long count)
-{
- return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
-}
-
-static inline long plpar_get_term_char(unsigned long termno,
- unsigned long *len_ret, char *buf_ret)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
- unsigned long *lbuf = (unsigned long *)buf_ret; /* TODO: alignment? */
-
- rc = plpar_hcall(H_GET_TERM_CHAR, retbuf, termno);
-
- *len_ret = retbuf[0];
- lbuf[0] = retbuf[1];
- lbuf[1] = retbuf[2];
-
- return rc;
-}
-
-static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
- const char *buffer)
-{
- unsigned long *lbuf = (unsigned long *)buffer; /* TODO: alignment? */
- return plpar_hcall_norets(H_PUT_TERM_CHAR, termno, len, lbuf[0],
- lbuf[1]);
-}
-
-/* Set various resource mode parameters */
-static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
- unsigned long value1, unsigned long value2)
-{
- return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
-}
-
-/*
- * Enable relocation on exceptions on this partition
- *
- * Note: this call has a partition wide scope and can take a while to complete.
- * If it returns H_LONG_BUSY_* it should be retried periodically until it
- * returns H_SUCCESS.
- */
-static inline long enable_reloc_on_exceptions(void)
-{
- /* mflags = 3: Exceptions at 0xC000000000004000 */
- return plpar_set_mode(3, 3, 0, 0);
-}
-
-/*
- * Disable relocation on exceptions on this partition
- *
- * Note: this call has a partition wide scope and can take a while to complete.
- * If it returns H_LONG_BUSY_* it should be retried periodically until it
- * returns H_SUCCESS.
- */
-static inline long disable_reloc_on_exceptions(void) {
- return plpar_set_mode(0, 3, 0, 0);
-}
-
-static inline long plapr_set_ciabr(unsigned long ciabr)
-{
- return plpar_set_mode(0, 1, ciabr, 0);
-}
-
-static inline long plapr_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
-{
- return plpar_set_mode(0, 2, dawr0, dawrx0);
-}
-
-#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index ca70279..c905b99 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -18,8 +18,7 @@
#include <asm/machdep.h>
#include <asm/firmware.h>
#include <asm/runlatch.h>
-
-#include "plpar_wrappers.h"
+#include <asm/plpar_wrappers.h>
struct cpuidle_driver pseries_idle_driver = {
.name = "pseries_idle",
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index c11c823..4291589 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -66,8 +66,8 @@
#include <asm/firmware.h>
#include <asm/eeh.h>
#include <asm/reg.h>
+#include <asm/plpar_wrappers.h>
-#include "plpar_wrappers.h"
#include "pseries.h"
int CMO_PrPSP = -1;
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 306643c..1c79af7 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -43,8 +43,8 @@
#include <asm/cputhreads.h>
#include <asm/xics.h>
#include <asm/dbell.h>
+#include <asm/plpar_wrappers.h>
-#include "plpar_wrappers.h"
#include "pseries.h"
#include "offline_states.h"
^ permalink raw reply related
* [PATCH V5 1/5] pseries/cpuidle: Remove dependency of pseries.h file
From: Deepthi Dharwar @ 2013-08-22 9:53 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
In-Reply-To: <20130822095323.27416.79369.stgit@deepthi.in.ibm.com>
As a part of pseries_idle cleanup to make the backend driver
code common to both pseries and powernv.
Remove non-essential smt_snooze_delay declaration in pseries.h
header file and pseries.h file inclusion in
pseries/processor_idle.c
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
arch/powerpc/platforms/pseries/processor_idle.c | 1 -
arch/powerpc/platforms/pseries/pseries.h | 3 ---
2 files changed, 4 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index 4644efa0..ca70279 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -20,7 +20,6 @@
#include <asm/runlatch.h>
#include "plpar_wrappers.h"
-#include "pseries.h"
struct cpuidle_driver pseries_idle_driver = {
.name = "pseries_idle",
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index c2a3a25..d1b07e6 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -60,9 +60,6 @@ extern struct device_node *dlpar_configure_connector(u32);
extern int dlpar_attach_node(struct device_node *);
extern int dlpar_detach_node(struct device_node *);
-/* Snooze Delay, pseries_idle */
-DECLARE_PER_CPU(long, smt_snooze_delay);
-
/* PCI root bridge prepare function override for pseries */
struct pci_host_bridge;
int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);
^ permalink raw reply related
* [PATCH V5 0/5] POWER/cpuidle: Generic IBM-POWER cpuidle driver enabled for PSERIES and POWERNV platforms
From: Deepthi Dharwar @ 2013-08-22 9:53 UTC (permalink / raw)
To: benh, daniel.lezcano, linux-kernel, scottwood, linux-pm,
linuxppc-dev
Cc: preeti, dongsheng.wang
This patch series consolidates the backend cpuidle driver for pSeries
and powernv platforms with minimal code duplication.
Current existing backend driver for pseries has been moved to drivers/cpuidle
and has been extended to accommodate powernv idle power mgmt states.
As seen in V1 of this patch series, having a separate powernv backend driver
results in too much code duplication, which is less elegant and can pose
maintenance problems going further.
Using the cpuidle framework to exploit platform low power idle states
management can take advantage of advanced heuristics, tunables and features
provided by framework. The statistics and tracing infrastructure provided
by the cpuidle framework also helps in enabling power management
related tools and help tune the system and applications.
Earlier in 3.3 kernel, pSeries idle state management was modified to
exploit the cpuidle framework and the end goal of this patch is to have powernv
platform also to hook its idle states into cpuidle framework with minimal
code duplication between both platforms.
This series aims to maintain compatibility and functionality to existing pseries
and powernv idle cpu management code. There are no new functions or idle
states added as part of this series. This can be extended by adding more
states to this existing framework.
This patch series has been tested on both PSERIES and POWERNV
platform and is based on v3.11-rc6 kernel version.
With this patch series, the powernv cpuidle functionalities are on-par with
pSeries idle management.
V1 -> http://lkml.org/lkml/2013/7/23/143
V2 -> https://lkml.org/lkml/2013/7/30/872
V3 -> http://comments.gmane.org/gmane.linux.ports.ppc.embedded/63093
V4 -> https://lkml.org/lkml/2013/8/22/25
Changes in V5:
=============
* As per the discussions in the community, this patch series
enables cpuidle backend driver only for IBM-POWER
platforms. File is re-named from drivers/cpuidle/cpuidle-powerpc.c
to drivers/cpuidle/cpuildle-ibm-power.c
New back-end cpuidle driver is called IBM-POWER-Idle.
* General cleanups on the accessors front that was introduced in
previous version.
Changes in V4:
=============
* This patch series includes generic backend driver cpuidle cleanups
including, replacing the driver and device initialisation
routines with cpuidle_register function.
* Enable CPUIDLE framework only for POWER and POWERNV platforms.
Changes in V3:
=============
* This patch series does not include smt-snooze-delay fixes.
This will be taken up later on.
* Integrated POWERPC driver in drivers/cpuidle. Enabled for all of
POWERPC platform. Currently has PSERIES and POWERNV support.
No compile time flags in .c file. This will be one consolidated
binary that does a run time detection based on platform and take
decisions accordingly.
* Enabled CPUIDLE framwork for all of PPC64.
Changes in V2:
=============
* Merged the backend driver posted out for powernv in V1 with
pSeries to create a single powerpc driver but this had compile
time flags.
Deepthi Dharwar (5):
pseries/cpuidle: Remove dependency of pseries.h file
pseries: Move plpar_wrapper.h to powerpc common include/asm location.
POWER/cpuidle: Generic IBM-POWER backend cpuidle driver.
POWER/cpuidle: Enable powernv cpuidle support.
powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
arch/powerpc/include/asm/plpar_wrappers.h | 325 +++++++++++++++++++++
arch/powerpc/include/asm/processor.h | 2
arch/powerpc/platforms/powernv/setup.c | 14 +
arch/powerpc/platforms/pseries/Kconfig | 9 -
arch/powerpc/platforms/pseries/Makefile | 1
arch/powerpc/platforms/pseries/cmm.c | 3
arch/powerpc/platforms/pseries/dtl.c | 3
arch/powerpc/platforms/pseries/hotplug-cpu.c | 3
arch/powerpc/platforms/pseries/hvconsole.c | 2
arch/powerpc/platforms/pseries/iommu.c | 3
arch/powerpc/platforms/pseries/kexec.c | 2
arch/powerpc/platforms/pseries/lpar.c | 2
arch/powerpc/platforms/pseries/plpar_wrappers.h | 324 ---------------------
arch/powerpc/platforms/pseries/processor_idle.c | 362 -----------------------
arch/powerpc/platforms/pseries/pseries.h | 3
arch/powerpc/platforms/pseries/setup.c | 2
arch/powerpc/platforms/pseries/smp.c | 2
drivers/cpuidle/Kconfig | 7
drivers/cpuidle/Makefile | 2
drivers/cpuidle/cpuidle-ibm-power.c | 335 +++++++++++++++++++++
20 files changed, 693 insertions(+), 713 deletions(-)
create mode 100644 arch/powerpc/include/asm/plpar_wrappers.h
delete mode 100644 arch/powerpc/platforms/pseries/plpar_wrappers.h
delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
create mode 100644 drivers/cpuidle/cpuidle-ibm-power.c
-- Deepthi
^ permalink raw reply
* Re: [PATCH v10 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Mark Brown @ 2013-08-22 9:45 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, lars, swarren, festevam,
s.hauer, timur, rob.herring, tomasz.figa, p.zabel, R65777,
shawn.guo, linuxppc-dev
In-Reply-To: <03182ed7464c156ec6345194d3f7ec920f753c2f.1377054540.git.b42378@freescale.com>
[-- Attachment #1: Type: text/plain, Size: 222 bytes --]
On Wed, Aug 21, 2013 at 11:13:16AM +0800, Nicolin Chen wrote:
> This patch implements a device-tree-only CPU DAI driver for Freescale
> S/PDIF controller that supports stereo playback and record feature.
Applied, thanks.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 7/7] drivers: base: refactor add_memory_section() to add_memory_block()
From: Yasuaki Ishimatsu @ 2013-08-22 8:20 UTC (permalink / raw)
To: Seth Jennings
Cc: Dave Hansen, Lai Jiangshan, linuxppc-dev, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, linux-mm, Yinghai Lu,
Nathan Fontenot, Andrew Morton, Cody P Schafer, Wanpeng Li
In-Reply-To: <1377018783-26756-7-git-send-email-sjenning@linux.vnet.ibm.com>
(2013/08/21 2:13), Seth Jennings wrote:
> Right now memory_dev_init() maintains the memory block pointer
> between iterations of add_memory_section(). This is nasty.
>
> This patch refactors add_memory_section() to become add_memory_block().
> The refactoring pulls the section scanning out of memory_dev_init()
> and simplifies the signature.
>
> Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com>
> ---
> drivers/base/memory.c | 48 +++++++++++++++++++++---------------------------
> 1 file changed, 21 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/base/memory.c b/drivers/base/memory.c
> index 7d9d3bc..021283a 100644
> --- a/drivers/base/memory.c
> +++ b/drivers/base/memory.c
> @@ -602,32 +602,31 @@ static int init_memory_block(struct memory_block **memory,
> return ret;
> }
>
> -static int add_memory_section(struct mem_section *section,
> - struct memory_block **mem_p)
> +static int add_memory_block(int base_section_nr)
> {
> - struct memory_block *mem = NULL;
> - int scn_nr = __section_nr(section);
> - int ret = 0;
> -
> - if (mem_p && *mem_p) {
> - if (scn_nr >= (*mem_p)->start_section_nr &&
> - scn_nr <= (*mem_p)->end_section_nr) {
> - mem = *mem_p;
> - }
> - }
> + struct memory_block *mem;
> + int i, ret, section_count = 0, section_nr;
>
> - if (mem)
> - mem->section_count++;
> - else {
> - ret = init_memory_block(&mem, section, MEM_ONLINE);
> - /* store memory_block pointer for next loop */
> - if (!ret && mem_p)
> - *mem_p = mem;
> + for (i = base_section_nr;
> + (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
> + i++) {
> + if (!present_section_nr(i))
> + continue;
> + if (section_count == 0)
> + section_nr = i;
> + section_count++;
> }
>
> - return ret;
> + if (section_count == 0)
> + return 0;
> + ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
> + if (ret)
> + return ret;
> + mem->section_count = section_count;
> + return 0;
> }
>
> +
> /*
> * need an interface for the VM to add new memory regions,
> * but without onlining it.
> @@ -733,7 +732,6 @@ int __init memory_dev_init(void)
> int ret;
> int err;
> unsigned long block_sz;
> - struct memory_block *mem = NULL;
>
> ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
> if (ret)
> @@ -747,12 +745,8 @@ int __init memory_dev_init(void)
> * during boot and have been initialized
> */
> mutex_lock(&mem_sysfs_mutex);
> - for (i = 0; i < NR_MEM_SECTIONS; i++) {
> - if (!present_section_nr(i))
> - continue;
> - /* don't need to reuse memory_block if only one per block */
> - err = add_memory_section(__nr_to_section(i),
> - (sections_per_block == 1) ? NULL : &mem);
> + for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {
Why do you remove present_setcion_nr() check?
> + err = add_memory_block(i);
> if (!ret)
Thanks,
Yasuaki Ishimatasu
> ret = err;
> }
>
^ permalink raw reply
* Re: [RFC V2 PATCH 4/6] cpuidle/ppc: Add longnap state to the idle states on powernv
From: Preeti U Murthy @ 2013-08-22 9:09 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
linuxppc-dev
In-Reply-To: <1377142130.25016.273.camel@pasglop>
Hi Ben,
On 08/22/2013 08:58 AM, Benjamin Herrenschmidt wrote:
> On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:
>> This patch hooks into the existing broadcast framework along with the support
>> that this patchset introduces for ppc, and the cpuidle driver backend
>> for powernv(posted out by Deepthi Dharwar:https://lkml.org/lkml/2013/7/23/128)
>> to add sleep state as one of the deep idle states, in which the decrementer
>> is switched off.
>>
>> However in this patch, we only emulate sleep by going into a state which does
>> a nap with the decrementer interrupts disabled, termed as longnap. This enables
>> focus on the timer broadcast framework for ppc in this series of patches ,
>> which is required as a first step to enable sleep on ppc.
>
> This is only for debug / proof of concept right ? We should use a real
> sleep here.
>
> If we need to know whether the FW supports it (PORE etc...) we shall add
> a device-tree property from the FW to indicate that fact.
We also need the sleep support right? The context management, I mean.
Yes it is a debug patch, so as to first ensure that we have the hook up
to the broadcast framework done right.
Regards
Preeti U Murthy
^ permalink raw reply
* Re: [RFC V2 PATCH 3/6] cpuidle/ppc: Add timer offload framework to support deep idle states
From: Preeti U Murthy @ 2013-08-22 9:03 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: fweisbec, paul.gortmaker, paulus, shangw, rjw, paulmck, arnd,
linux-pm, rostedt, john.stultz, tglx, chenhui.zhao, deepthi,
r58472, geoff, linux-kernel, srivatsa.bhat, schwidefsky,
linuxppc-dev
In-Reply-To: <1377142037.25016.272.camel@pasglop>
Hi Ben,
On 08/22/2013 08:57 AM, Benjamin Herrenschmidt wrote:
> On Wed, 2013-08-14 at 17:26 +0530, Preeti U Murthy wrote:
>
>> static irqreturn_t timer_action(int irq, void *data)
>> {
>> - timer_interrupt();
>> + decrementer_timer_interrupt();
>> return IRQ_HANDLED;
>> }
>
> I don't completely understand what you are doing here, but ...
>
>> @@ -223,7 +223,7 @@ irqreturn_t smp_ipi_demux(void)
>>
>> #ifdef __BIG_ENDIAN
>> if (all & (1 << (24 - 8 * PPC_MSG_TIMER)))
>> - timer_interrupt();
>> + decrementer_timer_interrupt();
>
> Why call this decrementer_* since it's specifically *not* the
> decrementer ?
>
> Makes more sense to be called broadcast_timer_interrupt() no ?
A broadcast IPI is meant to trigger timer interrupt handling on the
target CPUs. In deep idle states, even though the local timers of CPUs
become non-functional, it should not make a difference to them because
of the broadcast framework's help.
The broadcast framework is meant to hide the fact that the CPUs in deep
idle states require external help to wakeup on their expired timer
events. So the CPUs should wake up to find themselves handling the
timers under such a scenario, although they woke up from an IPI.
This whole idea gets conveyed by naming the handler of the broadcast IPI
to decrementer_timer_interrupt().
That said, ideally it should have been called timer_interrupt(). But
since we already have the timer interrupt handler with the same name,
and also we cannot call it directly for reasons mentioned in the reply
to your review on PATCH 2/6, I named it decrementer_timer_interrupt() to
come close to conveying the idea. This calls only the timer interrupt
handler there.
>
>> if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
>> scheduler_ipi();
>> if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
>> diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
>> index 65ab9e9..7e858e1 100644
>> --- a/arch/powerpc/kernel/time.c
>> +++ b/arch/powerpc/kernel/time.c
>> @@ -42,6 +42,7 @@
>> #include <linux/timex.h>
>> #include <linux/kernel_stat.h>
>> #include <linux/time.h>
>> +#include <linux/timer.h>
>> #include <linux/init.h>
>> #include <linux/profile.h>
>> #include <linux/cpu.h>
>> @@ -97,8 +98,11 @@ static struct clocksource clocksource_timebase = {
>>
>> static int decrementer_set_next_event(unsigned long evt,
>> struct clock_event_device *dev);
>> +static int broadcast_set_next_event(unsigned long evt,
>> + struct clock_event_device *dev);
>> static void decrementer_set_mode(enum clock_event_mode mode,
>> struct clock_event_device *dev);
>> +static void decrementer_timer_broadcast(const struct cpumask *mask);
>>
>> struct clock_event_device decrementer_clockevent = {
>> .name = "decrementer",
>> @@ -106,13 +110,26 @@ struct clock_event_device decrementer_clockevent = {
>> .irq = 0,
>> .set_next_event = decrementer_set_next_event,
>> .set_mode = decrementer_set_mode,
>> - .features = CLOCK_EVT_FEAT_ONESHOT,
>> + .broadcast = decrementer_timer_broadcast,
>> + .features = CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_ONESHOT,
>> };
>> EXPORT_SYMBOL(decrementer_clockevent);
>>
>> +struct clock_event_device broadcast_clockevent = {
>> + .name = "broadcast",
>> + .rating = 200,
>> + .irq = 0,
>> + .set_next_event = broadcast_set_next_event,
>> + .set_mode = decrementer_set_mode,
>
> Same here, why "decrementer" ? This event device is *not* the
> decrementer right ?
You are right. In this case it should have been broadcast_set_mode. This
is because this function is associated with the sender(the broadcast cpu).
>
> Also, pardon my ignorance, by why do we need a separate
> clock_event_device ? Ie what does that do ? I am not familiar with the
> broadcast scheme and what .broadcast do in the "decrementer" one, so
> you need to provide me at least with better explanations.
The answer in short to why we need an additional clock event device is
that, in this patchset, we try to integrate the support for deep sleep
states in power, with the broadcast framework existent today in the
kernel without any changes to this broadcast framework and trying our
best to adapt to it. Let me now elaborate.
The broadcast framework kicks in if there is a broadcast clock event
device. We can double up the local timer/decrementer of a CPU as the
broadcast clock event device itself. But the broadcast framework
considers a clock event device an eligible candidate for broadcast, if
the feature CLOCK_EVT_FEAT_C3STOP is not associated with it. This
feature says that the clock event device stops in deep idle states. The
broadcast framework expects the clock event device which takes up the
responsibility of doing broadcast to be available and on at all points
in time.
The decrementer clock event device however is susceptible to
non-availability in deep idle states.
Now the next question of why does a broadcast framework require a clock
event device? This clock event device is the equivalent of the local
timer of a CPU, except that this behaves like the global timer for all
CPUs whose local timers are non-functional. Of course this timer can
wakeup only one CPU on expiry. So the CPU chosen for this purpose will
effectively have two devices, the local clock event device and the
broadcast clock event device targeting their interrupts to it. When the
broadcast clock event device interrupts the CPU, the CPU sends an IPI to
those of the idling CPUs whose local timers have stopped, if required,
with an intention of waking them up to handle their local timer events.
The job of the broadcast framework is to find out which CPU, that has
its local timers switched off has to be woken up next. The important
thing to note here is that the local timers are not expected to be
switched off only in deep idle states. They can be non functional due to
whatever reason, at which time they come to broadcast framework seeking
help; to wake them up at their local timer events.
The broadcast framework puts the CPUs under such a category, into a mask
and each time a new CPU enters such a mask, it reprograms the broadcast
clock event device to the earliest of the new wakeup and the old. If the
local timer of a CPU was also used for this purpose, its original local
wakeup event would be overwritten.
On powerpc, since we do not have a physical clock event device
additionally to the local clock event devices, we need to have a pseudo
device so that we can activate the broadcast framework.
I will explain what the .broadcast in decrementer clock event device
does further down in the mail.
>
>> + .features = CLOCK_EVT_FEAT_ONESHOT,
>> +};
>> +EXPORT_SYMBOL(broadcast_clockevent);
>> +
>> DEFINE_PER_CPU(u64, decrementers_next_tb);
>> static DEFINE_PER_CPU(struct clock_event_device, decrementers);
>> +static DEFINE_PER_CPU(struct clock_event_device, bc_timer);
>
> Do we really need an additional per CPU here ? What does the bc_timer
> actually represent ? The sender (broadcaster) or receiver ? In the
> latter case, why does it have to differ from the decrementer ?
No we dont really need this to be per cpu. The PATCH 4/6 removes this
per_cpu instance, instead has one clock event device. The bc_timer is
the broadcast clock event device that is described above. So to answer
the above question it is associated with the sender. It needs to be
different from the decrementer for the reasons mentioned above.
>
>> +int bc_cpu;
>
> A global with that name ? Exported ? That's gross...
Sorry about this, ill take care of the implementation of this in the
next version by adding accessor functions to set/unset it.
>
>> #define XSEC_PER_SEC (1024*1024)
>>
>> #ifdef CONFIG_PPC64
>> @@ -487,6 +504,8 @@ void timer_interrupt(struct pt_regs * regs)
>> struct pt_regs *old_regs;
>> u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
>> struct clock_event_device *evt = &__get_cpu_var(decrementers);
>> + struct clock_event_device *bc_evt = &__get_cpu_var(bc_timer);
>> + int cpu = smp_processor_id();
>> u64 now;
>>
>> /* Ensure a positive value is written to the decrementer, or else
>> @@ -532,6 +551,10 @@ void timer_interrupt(struct pt_regs * regs)
>> *next_tb = ~(u64)0;
>> if (evt->event_handler)
>> evt->event_handler(evt);
>> + if (cpu == bc_cpu && bc_evt->event_handler) {
>> + bc_evt->event_handler(bc_evt);
>> + }
>> +
>
> So here, on a CPU that happens to be "bc_cpu", we call an additional
> "event_handler" on every timer interrupt ? What does that handler
> actually do ? How does it relate to the "broadcast" field in the
> original clock source ?
This handler is in charge of finding out which of the CPUs whose local
timers have been switched off, need to be woken up to enable them to
handle their expired timer events. The bc_cpu sends an IPI to such
sleeping CPUs.
The broadcast framework currently uses the *broadcast* function to send
IPIs to the CPUs in deep idle states. This function needs to be
associated with the local timers of the CPUs according to the current
design of the broadcast framework.
So the event handler of the broadcast clock event device, uses the
broadcast function to send IPIs to the CPUs required, in addition to
finding out who to send the IPIs and when the next wakeup of idling CPUs
should be handled.
>
>> } else {
>> now = *next_tb - now;
>> if (now <= DECREMENTER_MAX)
>> @@ -806,6 +829,20 @@ static int decrementer_set_next_event(unsigned long evt,
>> return 0;
>> }
>>
>> +/*
>> + * We cannot program the decrementer of a remote CPU. Hence CPUs going into
>> + * deep idle states need to send IPIs to the broadcast CPU to program its
>> + * decrementer for their next local event so as to receive a broadcast IPI
>> + * for the same. In order to avoid the overhead of multiple CPUs from sending
>> + * IPIs, this function is a nop. Instead the broadcast CPU will handle the
>> + * wakeup of CPUs in deep idle states in each of its local timer interrupts.
>> + */
>> +static int broadcast_set_next_event(unsigned long evt,
>> + struct clock_event_device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> static void decrementer_set_mode(enum clock_event_mode mode,
>> struct clock_event_device *dev)
>> {
>> @@ -813,6 +850,20 @@ static void decrementer_set_mode(enum clock_event_mode mode,
>> decrementer_set_next_event(DECREMENTER_MAX, dev);
>> }
>>
>> +void decrementer_timer_interrupt(void)
>> +{
>> + struct clock_event_device *evt;
>> + evt = &per_cpu(decrementers, smp_processor_id());
>> +
>> + if (evt->event_handler)
>> + evt->event_handler(evt);
>> +}
>
> So that's what happens when we receive the broadcast... it might need
> some stats ... and it's using the normal "decrementer" clock source,
> so I still have a problem understanding why you need another one.
So this is the receiver part of the broadcast. The sender needs to call
the event handler of the broadcast clock event device while the receiver
has to invoke the event handler of the decrementer clock event device so
as to handle its local timer events.
But you are right, we are missing stats accumulation by doing the
above. I need to take care of this.
>
>> +static void decrementer_timer_broadcast(const struct cpumask *mask)
>> +{
>> + arch_send_tick_broadcast(mask);
>> +}
>
> Ok, so far so good. But that's also hooked into the normal clock
> source...
This broadcast function has to be associated with the normal clock
source according to the implementation of the broadcast framework. I am
not too sure about the reason behind this.
So the current implementation has the broadcast event handler associated
with the broadcast clock event device(where cpus that have to be woken
up are selected and the broadcast clock event device reprogrammed), and
the actual job of broadcasting is associated with the normal clock
source(sending an IPI), i.e. the .broadcast fn.
And the broadcast IPI handler on the target CPUs has to invoke the timer
handler of the nromal clock source.
So only the broadcast event handler(tick_handle_oneshot_broadcast() and
tick_handle_periodic_broadcast()) is associated with the broadcast clock
source.
Regards
Preeti U Murthy
^ permalink raw reply
* Re: [PATCH 1/7] drivers: base: move mutex lock out of add_memory_section()
From: Yasuaki Ishimatsu @ 2013-08-22 8:44 UTC (permalink / raw)
To: Seth Jennings
Cc: Dave Hansen, Lai Jiangshan, linuxppc-dev, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, linux-mm, Yinghai Lu,
Nathan Fontenot, Andrew Morton, Cody P Schafer, Wanpeng Li
In-Reply-To: <20130820172445.GE4151@medulla.variantweb.net>
(2013/08/21 2:24), Seth Jennings wrote:
> Gah! Forgot the cover letter.
>
> This patchset just seeks to clean up and refactor some things in
> memory.c for better understanding and possibly better performance due do
> a decrease in mutex acquisitions and refcount churn at boot time. No
> functional change is intended by this set!
All patches were
Reviewed-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Tested-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Thanks,
Yasuaki Ishimatsu
>
> Seth
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org. For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
>
^ permalink raw reply
* Re: [PATCH 7/7] drivers: base: refactor add_memory_section() to add_memory_block()
From: Yasuaki Ishimatsu @ 2013-08-22 8:30 UTC (permalink / raw)
To: Seth Jennings
Cc: Dave Hansen, Lai Jiangshan, linuxppc-dev, Greg Kroah-Hartman,
Rafael J. Wysocki, linux-kernel, linux-mm, Yinghai Lu,
Nathan Fontenot, Andrew Morton, Cody P Schafer, Wanpeng Li
In-Reply-To: <5215C9B3.4090608@jp.fujitsu.com>
(2013/08/22 17:20), Yasuaki Ishimatsu wrote:
> (2013/08/21 2:13), Seth Jennings wrote:
>> Right now memory_dev_init() maintains the memory block pointer
>> between iterations of add_memory_section(). This is nasty.
>>
>> This patch refactors add_memory_section() to become add_memory_block().
>> The refactoring pulls the section scanning out of memory_dev_init()
>> and simplifies the signature.
>>
>> Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com>
>> ---
>> drivers/base/memory.c | 48 +++++++++++++++++++++---------------------------
>> 1 file changed, 21 insertions(+), 27 deletions(-)
>>
>> diff --git a/drivers/base/memory.c b/drivers/base/memory.c
>> index 7d9d3bc..021283a 100644
>> --- a/drivers/base/memory.c
>> +++ b/drivers/base/memory.c
>> @@ -602,32 +602,31 @@ static int init_memory_block(struct memory_block **memory,
>> return ret;
>> }
>>
>> -static int add_memory_section(struct mem_section *section,
>> - struct memory_block **mem_p)
>> +static int add_memory_block(int base_section_nr)
>> {
>> - struct memory_block *mem = NULL;
>> - int scn_nr = __section_nr(section);
>> - int ret = 0;
>> -
>> - if (mem_p && *mem_p) {
>> - if (scn_nr >= (*mem_p)->start_section_nr &&
>> - scn_nr <= (*mem_p)->end_section_nr) {
>> - mem = *mem_p;
>> - }
>> - }
>> + struct memory_block *mem;
>> + int i, ret, section_count = 0, section_nr;
>>
>> - if (mem)
>> - mem->section_count++;
>> - else {
>> - ret = init_memory_block(&mem, section, MEM_ONLINE);
>> - /* store memory_block pointer for next loop */
>> - if (!ret && mem_p)
>> - *mem_p = mem;
>> + for (i = base_section_nr;
>> + (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
>> + i++) {
>> + if (!present_section_nr(i))
>> + continue;
>> + if (section_count == 0)
>> + section_nr = i;
>> + section_count++;
>> }
>>
>> - return ret;
>> + if (section_count == 0)
>> + return 0;
>> + ret = init_memory_block(&mem, __nr_to_section(section_nr), MEM_ONLINE);
>> + if (ret)
>> + return ret;
>> + mem->section_count = section_count;
>> + return 0;
>> }
>>
>> +
>> /*
>> * need an interface for the VM to add new memory regions,
>> * but without onlining it.
>> @@ -733,7 +732,6 @@ int __init memory_dev_init(void)
>> int ret;
>> int err;
>> unsigned long block_sz;
>> - struct memory_block *mem = NULL;
>>
>> ret = subsys_system_register(&memory_subsys, memory_root_attr_groups);
>> if (ret)
>> @@ -747,12 +745,8 @@ int __init memory_dev_init(void)
>> * during boot and have been initialized
>> */
>> mutex_lock(&mem_sysfs_mutex);
>> - for (i = 0; i < NR_MEM_SECTIONS; i++) {
>> - if (!present_section_nr(i))
>> - continue;
>> - /* don't need to reuse memory_block if only one per block */
>> - err = add_memory_section(__nr_to_section(i),
>> - (sections_per_block == 1) ? NULL : &mem);
>> + for (i = 0; i < NR_MEM_SECTIONS; i += sections_per_block) {
>
> Why do you remove present_setcion_nr() check?
Sorry for the noise. I understood.
The check was moved into add_memory_section(). So it was removed.
Thanks,
Yasuaki Ishimatsu
>
>> + err = add_memory_block(i);
>> if (!ret)
>
> Thanks,
> Yasuaki Ishimatasu
>
>> ret = err;
>> }
>>
>
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org. For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
>
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/iommu: check dev->iommu_group before remove a device from iommu_group
From: Wei Yang @ 2013-08-22 7:52 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: alex.williamson, paulus, benh, linuxppc-dev, linux-kernel
In-Reply-To: <5215BC76.10105@ozlabs.ru>
On Thu, Aug 22, 2013 at 05:23:34PM +1000, Alexey Kardashevskiy wrote:
>On 08/19/2013 11:55 AM, Wei Yang wrote:
>> On Mon, Aug 19, 2013 at 11:39:49AM +1000, Alexey Kardashevskiy wrote:
>>> On 08/19/2013 11:29 AM, Wei Yang wrote:
>>>> On Fri, Aug 16, 2013 at 08:15:36PM +1000, Alexey Kardashevskiy wrote:
>>>>> On 08/16/2013 08:08 PM, Wei Yang wrote:
>>>>>> ---
>>>>>> arch/powerpc/kernel/iommu.c | 3 ++-
>>>>>> 1 files changed, 2 insertions(+), 1 deletions(-)
>>>>>>
>>>>>> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
>>>>>> index b20ff17..5abf7c3 100644
>>>>>> --- a/arch/powerpc/kernel/iommu.c
>>>>>> +++ b/arch/powerpc/kernel/iommu.c
>>>>>> @@ -1149,7 +1149,8 @@ static int iommu_bus_notifier(struct notifier_block *nb,
>>>>>> case BUS_NOTIFY_ADD_DEVICE:
>>>>>> return iommu_add_device(dev);
>>>>>> case BUS_NOTIFY_DEL_DEVICE:
>>>>>> - iommu_del_device(dev);
>>>>>> + if (dev->iommu_group)
>>>>>> + iommu_del_device(dev);
>>>>>> return 0;
>>>>>> default:
>>>>>> return 0;
>>>>>>
>>>>>
>>>>> This one seems redundant, no?
>>>>
>>>> Sorry for the late.
>>>>
>>>> Yes, these two patches have the same purpose to guard the system, while in two
>>>> different places. One is in powernv platform, the other is in the generic iommu
>>>> driver.
>>>>
>>>> The one in powernv platform is used to correct the original logic.
>>>>
>>>> The one in generic iommu driver is to keep system safe in case other platform to
>>>> call iommu_group_remove_device() without the check.
>>>
>>>
>>> But I am moving bus notifier to powernv code (posted a patch last week,
>>> otherwise Freescale's IOMMU conflicted) so this won't be the case.
>>
>> Yes, I see the patch.
>>
>> This means other platforms, besides powernv, will check the dev->iommu_group
>> before remove the device? This would be a convention?
>>
>> If this is the case, the second patch is enough. We don't need to check it in
>> generic iommu driver.
>>
>> Since I am not very familiar with the code convention, I post these two
>> patches together. This doesn't mean I need to push both of them. Your comments
>> are welcome, lets me understand which one is more suitable in this case.
>
>
>Ok. So. I included the check in the bus notifier which I moved to powernv
>platform, I guess I'll repost the series soon.
Thanks, this check will guard the powernv platform.
>
>Good luck with pushing the fix for drivers/iommu/iommu.c :)
>
Alex,
Sorry for not including you in the very beginning, which may spend you more
efforts to track previous mails in this thread.
Do you think it is reasonable to check the dev->iommu_group in
iommu_group_remove_device()? Or we can count on the bus notifier to check it?
Welcome your suggestions~
>
>
>--
>Alexey
--
Richard Yang
Help you, Help me
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/iommu: check dev->iommu_group before remove a device from iommu_group
From: Alexey Kardashevskiy @ 2013-08-22 7:23 UTC (permalink / raw)
To: Wei Yang; +Cc: paulus, benh, linuxppc-dev, linux-kernel
In-Reply-To: <20130819015538.GB8342@weiyang.vnet.ibm.com>
On 08/19/2013 11:55 AM, Wei Yang wrote:
> On Mon, Aug 19, 2013 at 11:39:49AM +1000, Alexey Kardashevskiy wrote:
>> On 08/19/2013 11:29 AM, Wei Yang wrote:
>>> On Fri, Aug 16, 2013 at 08:15:36PM +1000, Alexey Kardashevskiy wrote:
>>>> On 08/16/2013 08:08 PM, Wei Yang wrote:
>>>>> ---
>>>>> arch/powerpc/kernel/iommu.c | 3 ++-
>>>>> 1 files changed, 2 insertions(+), 1 deletions(-)
>>>>>
>>>>> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
>>>>> index b20ff17..5abf7c3 100644
>>>>> --- a/arch/powerpc/kernel/iommu.c
>>>>> +++ b/arch/powerpc/kernel/iommu.c
>>>>> @@ -1149,7 +1149,8 @@ static int iommu_bus_notifier(struct notifier_block *nb,
>>>>> case BUS_NOTIFY_ADD_DEVICE:
>>>>> return iommu_add_device(dev);
>>>>> case BUS_NOTIFY_DEL_DEVICE:
>>>>> - iommu_del_device(dev);
>>>>> + if (dev->iommu_group)
>>>>> + iommu_del_device(dev);
>>>>> return 0;
>>>>> default:
>>>>> return 0;
>>>>>
>>>>
>>>> This one seems redundant, no?
>>>
>>> Sorry for the late.
>>>
>>> Yes, these two patches have the same purpose to guard the system, while in two
>>> different places. One is in powernv platform, the other is in the generic iommu
>>> driver.
>>>
>>> The one in powernv platform is used to correct the original logic.
>>>
>>> The one in generic iommu driver is to keep system safe in case other platform to
>>> call iommu_group_remove_device() without the check.
>>
>>
>> But I am moving bus notifier to powernv code (posted a patch last week,
>> otherwise Freescale's IOMMU conflicted) so this won't be the case.
>
> Yes, I see the patch.
>
> This means other platforms, besides powernv, will check the dev->iommu_group
> before remove the device? This would be a convention?
>
> If this is the case, the second patch is enough. We don't need to check it in
> generic iommu driver.
>
> Since I am not very familiar with the code convention, I post these two
> patches together. This doesn't mean I need to push both of them. Your comments
> are welcome, lets me understand which one is more suitable in this case.
Ok. So. I included the check in the bus notifier which I moved to powernv
platform, I guess I'll repost the series soon.
Good luck with pushing the fix for drivers/iommu/iommu.c :)
--
Alexey
^ permalink raw reply
* Re: [PATCH v5 1/2] ASoC: fsl: Add S/PDIF CPU DAI driver
From: Mike Turquette @ 2013-08-22 7:19 UTC (permalink / raw)
To: Tomasz Figa, Mark Rutland
Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
lars@metafoo.de, ian.campbell@citrix.com, Pawel Moll,
swarren@wwwdotorg.org, festevam@gmail.com, Sascha Hauer,
Nicolin Chen, timur@tabi.org, rob.herring@calxeda.com,
broonie@kernel.org, p.zabel@pengutronix.de, galak@codeaurora.org,
shawn.guo@linaro.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <2207416.NJhrdSqkEZ@flatron>
Quoting Tomasz Figa (2013-08-21 14:34:55)
> On Wednesday 21 of August 2013 09:50:15 Mark Rutland wrote:
> > On Tue, Aug 20, 2013 at 01:06:25AM +0100, Mike Turquette wrote:
> > > Quoting Mark Rutland (2013-08-19 02:35:43)
> > > =
> > > > On Sat, Aug 17, 2013 at 04:17:18PM +0100, Tomasz Figa wrote:
> > > > > On Saturday 17 of August 2013 16:53:16 Sascha Hauer wrote:
> > > > > > On Sat, Aug 17, 2013 at 02:28:04PM +0200, Tomasz Figa wrote:
> > > > > > > > > > Also I would make this option required. Use a dummy
> > > > > > > > > > clock for
> > > > > > > > > > mux
> > > > > > > > > > inputs that are grounded for a specific SoC.
> > > > > > > > > =
> > > > > > > > > Some clocks are not from CCM and we haven't defined in
> > > > > > > > > imx6q-clk.txt,
> > > > > > > > > so in most cases we can't provide a phandle for them, eg:
> > > > > > > > > spdif_ext.
> > > > > > > > > I think it's a bit hard to force it to be 'required'. An
> > > > > > > > > 'optional'
> > > > > > > > > looks more flexible to me and a default one is ensured
> > > > > > > > > even if
> > > > > > > > > it's
> > > > > > > > > missing.
> > > > > > > > =
> > > > > > > > <&clks 0> is the dummy clock. This can be used for all input
> > > > > > > > clocks
> > > > > > > > not
> > > > > > > > defined by the SoC.
> > > > > > > =
> > > > > > > Where does this assumption come from? Is it documented
> > > > > > > anywhere?
> > > > > > =
> > > > > > This is how all i.MX clock bindings currently are. See
> > > > > > Documentation/devicetree/bindings/clock/imx*-clock.txt
> > > > > =
> > > > > OK, thanks.
> > > > > =
> > > > > I guess we need some discussion on dummy clocks vs skipped clocks.
> > > > > I think we want some consistency on this, don't we?
> > > > > =
> > > > > If we really need a dummy clock, then we might also want a generic
> > > > > way to specify it.
> > > > =
> > > > What do we actually mean by a "dummy clock"? We already have
> > > > bindings
> > > > for "fixed-clock" and co friends describe relatively simple
> > > > preconfigured clocks.
> > > =
> > > Some platforms have a fake clock which defines noops callbacks and
> > > basically doesn't do anything. This is analogous to the dummy
> > > regulator
> > > implementation. A central one could be registered by the clock core,
> > > as
> > > is done by the regulator core.
> > =
> > When you say some platforms, you presumably mean the platform code in
> > Linux? A dummy clock sounds like a completely Linux-specific abstraction
> > rather than a description of the hardware, and I don't see why we need
> > that in the DT:
> > =
> > * If a clock is wired up and running (as presumably the dummy clock is),
> > then surely it's a fixed-clock (it's running, we and we have no control
> > over it, but we presumably know its rate) and can be described as such?
> > =
> > * If no clock is wired up, then we should be able to describe that. If a
> > driver believes that a clock is required when it isn't (for some level
> > of functionality), then that driver should be fixed up to support the
> > clock as being optional.
> > =
> > Am I missing something?
> =
> I second that.
> =
> Moreover, I don't think that device tree should deal with dummy anything. =
> It should be able to describe hardware that is available on given system, =
> not list what hardware is not available.
I wasn't clear. The dummy clock IS a completely Linux-specific
abstraction.
I'm not advocating a dummy clock in DT. I am advocating consolidation of
the implementation of a clock that does nothing into the clock core.
This code could easily live in drivers/clk/clk.c instead of having
everyone open-code it.
As far as specifying a dummy clock in DT? I dunno. DT should describe
real hardware so there isn't much use for a dummy clock.
I'm guessing one of the reasons for such a clock are drivers do not
honor the clk.h api and they freak out when clk_get gives them a NULL
pointer?
Regards,
Mike
> =
> Best regards,
> Tomasz
^ 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