* RE: ppc/sata-fsl: orphan config value: CONFIG_MPC8315_DS
From: Xie Shaohui-B21989 @ 2013-08-27 10:51 UTC (permalink / raw)
To: Wood Scott-B07421, Anthony Foiani
Cc: Robert P.J.Day, linuxppc-dev@lists.ozlabs.org, Li Yang-Leo-R58472,
Adrian Bunk
In-Reply-To: <20130823192532.GA29205@home.buserror.net>
> As for the property name, I'd prefer "fsl,sata-speed-limit" or "fsl,sata-
> max-generation". Shaohui, do the driver bits look OK?
[S.H] The driver part is OK.=20
I also tested it on p5040, the SATA worked as expected.
Best Regards,=20
Shaohui Xie
^ permalink raw reply
* Re: [PATCH v8] KVM: PPC: reserve a capability and ioctl numbers for realmode VFIO
From: Gleb Natapov @ 2013-08-27 10:58 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: kvm, Alexander Graf, linux-kernel, Paul Mackerras, linuxppc-dev,
David Gibson
In-Reply-To: <521C666A.3020508@ozlabs.ru>
On Tue, Aug 27, 2013 at 06:42:18PM +1000, Alexey Kardashevskiy wrote:
> On 08/27/2013 05:56 PM, Gleb Natapov wrote:
> > On Thu, Aug 15, 2013 at 05:49:26PM +1000, Alexey Kardashevskiy wrote:
> >> This is to reserve a capablity number for upcoming support
> >> of VFIO-IOMMU DMA operations in real mode.
> >>
> >> The last ioctl in the group which KVM_CREATE_SPAPR_TCE_IOMMU is added to
> >> is 0xac, the next two numbers are taken - 0xad for KVM_KVMCLOCK_CTRL and
> > 0xac was also taken by KVM_SET_ONE_REG :(
> >
> >> 0xae for KVM_ARM_VCPU_INIT. So the KVM_CREATE_SPAPR_TCE_IOMMU ioclt gets
> >> 0xaf.
> >>
> >> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> >>
> >> ---
> >> Changes:
> >> 2013/08/15 v8:
> >> * fixed comment again
> >>
> >> 2013/08/15:
> >> * fixed mistype in comments
> >> * fixed commit message which says what uses ioctls 0xad and 0xae
> >>
> >> 2013/07/16:
> >> * changed the number
> >>
> >> 2013/07/11:
> >> * changed order in a file, added comment about a gap in ioctl number
> >> ---
> >> include/uapi/linux/kvm.h | 6 ++++++
> >> 1 file changed, 6 insertions(+)
> >>
> >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >> index 99c2533..bd94127 100644
> >> --- a/include/uapi/linux/kvm.h
> >> +++ b/include/uapi/linux/kvm.h
> >> @@ -668,6 +668,7 @@ struct kvm_ppc_smmu_info {
> >> #define KVM_CAP_IRQ_XICS 92
> >> #define KVM_CAP_ARM_EL1_32BIT 93
> >> #define KVM_CAP_SPAPR_MULTITCE 94
> >> +#define KVM_CAP_SPAPR_TCE_IOMMU 95
> >>
> >> #ifdef KVM_CAP_IRQ_ROUTING
> >>
> >> @@ -933,6 +934,11 @@ struct kvm_s390_ucas_mapping {
> >> #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr)
> >> /* Available with KVM_CAP_PPC_RTAS */
> >> #define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args)
> >> +/* 0xad is taken by KVM_KVMCLOCK_CTRL */
> >> +/* 0xae is taken by KVM_ARM_VCPU_INIT */
> >> +/* Available with KVM_CAP_SPAPR_TCE_IOMMU */
> >> +#define KVM_CREATE_SPAPR_TCE_IOMMU _IOW(KVMIO, 0xaf, \
> >> + struct kvm_create_spapr_tce_iommu)
> >>
> > Why not use KVM_CREATE_DEVICE API for that?
>
>
> Because when I came up with my ioctl first time, it was not in upstream and
> since then nobody pointed me to this new ioctl :)
Sorry about that :(. The ioctl exists for a while now, but with v8 patch I
imaging your patch series predates it.
> So my stuff is not going to upstream again. Heh. Ok. I'll implement it.
>
Thanks! Should I keep KVM_CAP_SPAPR_MULTITCE capability patch or can I
drop it for now?
--
Gleb.
^ permalink raw reply
* Re: [PATCH v8 1/3] DMA: Freescale: revise device tree binding document
From: Mark Rutland @ 2013-08-27 11:25 UTC (permalink / raw)
To: hongbo.zhang@freescale.com
Cc: devicetree@vger.kernel.org, ian.campbell@citrix.com, Pawel Moll,
swarren@wwwdotorg.org, vinod.koul@intel.com,
linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
djbw@fb.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377600123-5746-2-git-send-email-hongbo.zhang@freescale.com>
On Tue, Aug 27, 2013 at 11:42:01AM +0100, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>
> This patch updates the discription of each type of DMA controller and its
> channels, it is preparation for adding another new DMA controller binding, it
> also fixes some defects of indent for text alignment at the same time.
>
> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
> ---
> .../devicetree/bindings/powerpc/fsl/dma.txt | 62 +++++++++-----------
> 1 file changed, 27 insertions(+), 35 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> index 2a4b4bc..ddf17af 100644
> --- a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> +++ b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> @@ -1,33 +1,29 @@
> -* Freescale 83xx DMA Controller
> +* Freescale DMA Controllers
>
> -Freescale PowerPC 83xx have on chip general purpose DMA controllers.
> +** Freescale Elo DMA Controller
> + This is a little-endian DMA controller, used in Freescale mpc83xx series
> + chips such as mpc8315, mpc8349, mpc8379 etc.
>
> Required properties:
>
> -- compatible : compatible list, contains 2 entries, first is
> - "fsl,CHIP-dma", where CHIP is the processor
> - (mpc8349, mpc8360, etc.) and the second is
> - "fsl,elo-dma"
> -- reg : <registers mapping for DMA general status reg>
> -- ranges : Should be defined as specified in 1) to describe the
> - DMA controller channels.
> +- compatible : must include "fsl,elo-dma"
We should list the other values that may be in the list also, unless
they are really of no consequence, in which case their presence in dt is
questionable.
> +- reg : <registers specifier for DMA general status reg>
> +- ranges : describes the mapping between the address space of the
> + DMA channels and the address space of the DMA controller
> - cell-index : controller index. 0 for controller @ 0x8100
> -- interrupts : <interrupt mapping for DMA IRQ>
> +- interrupts : <interrupt specifier for DMA IRQ>
> - interrupt-parent : optional, if needed for interrupt mapping
>
> -
> - DMA channel nodes:
> - - compatible : compatible list, contains 2 entries, first is
> - "fsl,CHIP-dma-channel", where CHIP is the processor
> - (mpc8349, mpc8350, etc.) and the second is
> - "fsl,elo-dma-channel". However, see note below.
> - - reg : <registers mapping for channel>
> + - compatible : must include "fsl,elo-dma-channel"
> + However, see note below.
Again, I think we should list the other entries that may be in the list.
Otherwise it's not clear what the binding defines. Similarly for the
other compatible list definitions below...
> + - reg : <registers specifier for channel>
> - cell-index : dma channel index starts at 0.
I realise you haven't changed it, but it's unclear what the cell-index
property is (and somewhat confusingly there seem to be multiple
defnitions). It might be worth clarifying it while performing the other
cleanup.
>
> Optional properties:
> - - interrupts : <interrupt mapping for DMA channel IRQ>
> - (on 83xx this is expected to be identical to
> - the interrupts property of the parent node)
> + - interrupts : <interrupt specifier for DMA channel IRQ>
> + (on 83xx this is expected to be identical to
> + the interrupts property of the parent node)
> - interrupt-parent : optional, if needed for interrupt mapping
>
> Example:
> @@ -70,30 +66,26 @@ Example:
> };
> };
>
> -* Freescale 85xx/86xx DMA Controller
> -
> -Freescale PowerPC 85xx/86xx have on chip general purpose DMA controllers.
> +** Freescale EloPlus DMA Controller
> + This is DMA controller with extended addresses and chaining, mainly used in
> + Freescale mpc85xx/86xx, Pxxx and BSC series chips, such as mpc8540, mpc8641
> + p4080, bsc9131 etc.
>
> Required properties:
>
> -- compatible : compatible list, contains 2 entries, first is
> - "fsl,CHIP-dma", where CHIP is the processor
> - (mpc8540, mpc8540, etc.) and the second is
> - "fsl,eloplus-dma"
> -- reg : <registers mapping for DMA general status reg>
> +- compatible : must include "fsl,eloplus-dma"
> +- reg : <registers specifier for DMA general status reg>
> - cell-index : controller index. 0 for controller @ 0x21000,
> 1 for controller @ 0xc000
> -- ranges : Should be defined as specified in 1) to describe the
> - DMA controller channels.
> +- ranges : describes the mapping between the address space of the
> + DMA channels and the address space of the DMA controller
>
> - DMA channel nodes:
> - - compatible : compatible list, contains 2 entries, first is
> - "fsl,CHIP-dma-channel", where CHIP is the processor
> - (mpc8540, mpc8560, etc.) and the second is
> - "fsl,eloplus-dma-channel". However, see note below.
> + - compatible : must include "fsl,eloplus-dma-channel"
> + However, see note below.
> - cell-index : dma channel index starts at 0.
> - - reg : <registers mapping for channel>
> - - interrupts : <interrupt mapping for DMA channel IRQ>
> + - reg : <registers specifier for channel>
> + - interrupts : <interrupt specifier for DMA channel IRQ>
> - interrupt-parent : optional, if needed for interrupt mapping
>
> Example:
> --
> 1.7.9.5
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH v8 2/3] DMA: Freescale: Add new 8-channel DMA engine device tree nodes
From: Mark Rutland @ 2013-08-27 11:35 UTC (permalink / raw)
To: hongbo.zhang@freescale.com
Cc: devicetree@vger.kernel.org, ian.campbell@citrix.com, Pawel Moll,
swarren@wwwdotorg.org, vinod.koul@intel.com,
linux-kernel@vger.kernel.org, rob.herring@calxeda.com,
djbw@fb.com, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377600123-5746-3-git-send-email-hongbo.zhang@freescale.com>
On Tue, Aug 27, 2013 at 11:42:02AM +0100, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
>
> Freescale QorIQ T4 and B4 introduce new 8-channel DMA engines, this patch adds
> the device tree nodes for them.
>
> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
> ---
> .../devicetree/bindings/powerpc/fsl/dma.txt | 66 ++++++++++++++++
> arch/powerpc/boot/dts/fsl/b4si-post.dtsi | 4 +-
> arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi | 81 ++++++++++++++++++++
> arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi | 81 ++++++++++++++++++++
> arch/powerpc/boot/dts/fsl/t4240si-post.dtsi | 4 +-
> 5 files changed, 232 insertions(+), 4 deletions(-)
> create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
> create mode 100644 arch/powerpc/boot/dts/fsl/elo3-dma-1.dtsi
>
> diff --git a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> index ddf17af..10fd031 100644
> --- a/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> +++ b/Documentation/devicetree/bindings/powerpc/fsl/dma.txt
> @@ -126,6 +126,72 @@ Example:
> };
> };
>
> +** Freescale Elo3 DMA Controller
> + This is EloPlus controller with 8 channels, used in Freescale Txxx and Bxxx
> + series chips, such as t1040, t4240, b4860.
> +
> +Required properties:
> +
> +- compatible : must include "fsl,elo3-dma"
> +- reg : <registers specifier for DMA general status reg>
> +- ranges : describes the mapping between the address space of the
> + DMA channels and the address space of the DMA controller
> +
> +- DMA channel nodes:
> + - compatible : must include "fsl,eloplus-dma-channel"
> + - reg : <registers specifier for channel>
> + - interrupts : <interrupt specifier for DMA channel IRQ>
> + - interrupt-parent : optional, if needed for interrupt mapping
> +
> +Example:
> +dma@100300 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "fsl,elo3-dma";
> + reg = <0x100300 0x4 0x100600 0x4>;
Is that one reg entry where #size-cells=2 and #address-cells=2?
That's what the binding implies (given it only describes a single reg
entry).
if it's two entries, we should make that explicit (both in the binding
and example):
reg = <0x100300 0x4>,
<0x100600 0x4>;
> + ranges = <0x0 0x100100 0x500>;
If it is one reg entry then the example ranges property isn't big enough
to contain the parent-bus-address.
> + dma-channel@0 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x0 0x80>;
> + interrupts = <28 2 0 0>;
> + };
> + dma-channel@80 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x80 0x80>;
> + interrupts = <29 2 0 0>;
> + };
> + dma-channel@100 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x100 0x80>;
> + interrupts = <30 2 0 0>;
> + };
> + dma-channel@180 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x180 0x80>;
> + interrupts = <31 2 0 0>;
> + };
> + dma-channel@300 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x300 0x80>;
> + interrupts = <76 2 0 0>;
> + };
> + dma-channel@380 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x380 0x80>;
> + interrupts = <77 2 0 0>;
> + };
> + dma-channel@400 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x400 0x80>;
> + interrupts = <78 2 0 0>;
> + };
> + dma-channel@480 {
> + compatible = "fsl,eloplus-dma-channel";
> + reg = <0x480 0x80>;
> + interrupts = <79 2 0 0>;
> + };
> +};
> +
> Note on DMA channel compatible properties: The compatible property must say
> "fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
> driver (fsldma). Any DMA channel used by fsldma cannot be used by another
> diff --git a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
> index 7399154..ea53ea1 100644
> --- a/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
> +++ b/arch/powerpc/boot/dts/fsl/b4si-post.dtsi
> @@ -223,13 +223,13 @@
> reg = <0xe2000 0x1000>;
> };
>
> -/include/ "qoriq-dma-0.dtsi"
> +/include/ "elo3-dma-0.dtsi"
> dma@100300 {
> fsl,iommu-parent = <&pamu0>;
> fsl,liodn-reg = <&guts 0x580>; /* DMA1LIODNR */
> };
>
> -/include/ "qoriq-dma-1.dtsi"
> +/include/ "elo3-dma-1.dtsi"
> dma@101300 {
> fsl,iommu-parent = <&pamu0>;
> fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */
> diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
> new file mode 100644
> index 0000000..69a3277
> --- /dev/null
> +++ b/arch/powerpc/boot/dts/fsl/elo3-dma-0.dtsi
> @@ -0,0 +1,81 @@
> +/*
> + * QorIQ DMA device tree stub [ controller @ offset 0x100000 ]
Copy-pasted?
Presumably should be "Elo3 DMA devicetree stub", or similar?
Similarly for elo3-dma-1.dtsi.
Thanks,
Mark.
^ permalink raw reply
* Re: [PATCH][RFC] pci: fsl: rework PCIe driver compatible with Layerscape
From: Lian Minghuan-b31939 @ 2013-08-27 11:38 UTC (permalink / raw)
To: Scott Wood; +Cc: Minghuan Lian, linuxppc-dev, Zang Roy-R61911
In-Reply-To: <1377294311.20722.71.camel@snotra.buserror.net>
Hi Scott,
Thanks for your comments, please see my replies inline.
On 08/24/2013 05:45 AM, Scott Wood wrote:
> On Mon, 2013-08-19 at 20:23 +0800, Minghuan Lian wrote:
>> The Freescale's Layerscape series processors will use ARM cores.
>> The LS1's PCIe controllers is the same as T4240's. So it's better
>> the PCIe controller driver can support PowerPC and ARM
>> simultaneously. This patch is for this purpose. It derives
>> the common functions from arch/powerpc/sysdev/fsl_pci.c to
>> drivers/pci/host/pcie-fsl.c and leaves several platform-dependent
>> functions which should be implemented in platform files.
>>
>> Signed-off-by: Minghuan Lian<Minghuan.Lian@freescale.com>
>> ---
>> Based on upstream master 3.11-rc6
>> The function has been tested on P5020DS and P3041DS and T4240QDS boards
>> For mpc83xx and mpc86xx, I only did compile test.
> I assume you'll test on these (and older mpc85xx) before this becomes
> non-RFC?
[Minghuan] I will try to test on the relevant boards and list them.
>> arch/powerpc/Kconfig | 1 +
>> arch/powerpc/sysdev/fsl_pci.c | 591 ++++++----------------------------
>> arch/powerpc/sysdev/fsl_pci.h | 91 ------
>> drivers/edac/mpc85xx_edac.c | 10 -
>> drivers/pci/host/Kconfig | 4 +
>> drivers/pci/host/Makefile | 1 +
>> drivers/pci/host/pcie-fsl.c | 734 ++++++++++++++++++++++++++++++++++++++++++
>> include/linux/fsl/fsl-pcie.h | 176 ++++++++++
>> 8 files changed, 1008 insertions(+), 600 deletions(-)
>> create mode 100644 drivers/pci/host/pcie-fsl.c
>> create mode 100644 include/linux/fsl/fsl-pcie.h
> Please use -M -C with git format-patch.
>
> Why "pcie" rather than "pci"? Is non-express not supported by these new
> files?
[Minghuan] Using "pci" is more accurate. I selected 'pcie' because the
new file is
mainly for PCI Express controller, but it does contain two pci
boards(mpc8610,
mpc8540) support. I will change to 'pci'.
>> @@ -259,15 +258,6 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
>>
>> /* we only need the error registers */
>> r.start += 0xe00;
>> -
>> - if (!devm_request_mem_region(&op->dev, r.start, resource_size(&r),
>> - pdata->name)) {
>> - printk(KERN_ERR "%s: Error while requesting mem region\n",
>> - __func__);
>> - res = -EBUSY;
>> - goto err;
>> - }
>> -
>> pdata->pci_vbase = devm_ioremap(&op->dev, r.start, resource_size(&r));
>> if (!pdata->pci_vbase) {
>> printk(KERN_ERR "%s: Unable to setup PCI err regs\n", __func__);
> Could you explain this part?
[Minghuan] The new pci driver used devm_ioremap_resource() to map reg space.
So PCI EDAC driver would encounter an error when calling
devm_request_mem_region()
because pci device reg space has been assigned to pci driver. And EDAC
is only to
handler the error, has no reason to request exclusive PCI device reg space.
>> diff --git a/drivers/pci/host/pcie-fsl.c b/drivers/pci/host/pcie-fsl.c
>> new file mode 100644
>> index 0000000..6e767d4
>> --- /dev/null
>> +++ b/drivers/pci/host/pcie-fsl.c
>> @@ -0,0 +1,734 @@
>> +/*
>> + * 85xx/86xx/LS PCI/PCIE common driver support
>> + *
>> + * Copyright 2013 Freescale Semiconductor, Inc.
>> + *
>> + * Moved from arch/power/fsl_pci.c
> That's not the right pathname.
[Minghuan] Sorry, I will fix it.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2 of the License, or (at your
>> + * option) any later version.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/pci.h>
>> +#include <linux/string.h>
>> +#include <linux/init.h>
>> +#include <linux/log2.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_pci.h>
>> +#include <linux/pci_regs.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/resource.h>
>> +#include <linux/types.h>
>> +#include <linux/memblock.h>
>> +#include <linux/fsl/fsl-pcie.h>
> You don't need an "fsl-" prefix if it's in the "fsl/" directory.
[Minghuan] No, I will remove 'fsl-' prefix.
>> +static int fsl_pcie_write_config(struct fsl_pcie *pcie, int bus, int devfn,
>> + int offset, int len, u32 val)
>> +{
>> + void __iomem *cfg_data;
>> + u32 bus_no, reg;
>> +
>> + if (pcie->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) {
>> + if (bus != pcie->first_busno)
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> + if (devfn != 0)
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> + }
>> +
>> + if (fsl_pci_exclude_device(pcie, bus, devfn))
>> + return PCIBIOS_DEVICE_NOT_FOUND;
>> +
>> + bus_no = (bus == pcie->first_busno) ?
>> + pcie->self_busno : bus;
>> +
>> + if (pcie->indirect_type & INDIRECT_TYPE_EXT_REG)
>> + reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
>> + else
>> + reg = offset & 0xfc;
>> +
>> + if (pcie->indirect_type & INDIRECT_TYPE_BIG_ENDIAN)
>> + out_be32(&pcie->regs->config_addr,
>> + (0x80000000 | (bus_no << 16) | (devfn << 8) | reg));
>> + else
>> + out_le32(&pcie->regs->config_addr,
>> + (0x80000000 | (bus_no << 16) | (devfn << 8) | reg));
> Did you try building this on ARM? out_be32/le32() is PPC-specific. Use iowrite32be()/iowrite32().
[Minghuan] Yes. I will change them.
>> +ep_mode:
>> + dev_info(&pdev->dev, "It works as EP mode\n");
> This is a bit casually phrased... and where did this come from? This
> patch should just be about moving code around and removing PPC
> dependencies (ideally even those two would be separate). If there's
> new functionality or other changes it should be a separate patch.
[Minghuan] Sorry, I will continue using "no_bridge"
>> +static int __init fsl_pcie_probe(struct platform_device *pdev)
>> +{
>> + int ret;
>> + struct fsl_pcie *pcie;
>> +
>> + if (!of_device_is_available(pdev->dev.of_node)) {
>> + dev_err(&pdev->dev, "disabled\n");
>> + return -ENODEV;
>> + }
> That's not an error.
[Minghuan] Ok, I will fix it.
> -Scott
>
>
^ permalink raw reply
* Re: [alsa-devel] [PATCH v11] ASoC: fsl: Add S/PDIF machine driver
From: Mark Brown @ 2013-08-27 14:50 UTC (permalink / raw)
To: Nicolin Chen
Cc: mark.rutland, devicetree, alsa-devel, lars, Stephen Warren,
s.hauer, tomasz.figa, rob.herring, p.zabel, shawn.guo,
linuxppc-dev
In-Reply-To: <20130827020107.GB3758@MrMyself>
[-- Attachment #1: Type: text/plain, Size: 468 bytes --]
On Tue, Aug 27, 2013 at 10:01:08AM +0800, Nicolin Chen wrote:
> On Fri, Aug 23, 2013 at 08:13:53PM +0100, Mark Brown wrote:
> I think this patch hasn't been applied yet, already been acked though.
> Is there any problem in it?
You've allowed less than one working day for a response here - Monday
was a holiday in the UK. Something like a week is normally a minimum
for this sort of thing, especially in a case like this where there has
been extensive discussion.
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* RE: [alsa-devel] [PATCH v11] ASoC: fsl: Add S/PDIF machine driver
From: Chen Guangyu-B42378 @ 2013-08-27 15:15 UTC (permalink / raw)
To: Mark Brown
Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
alsa-devel@alsa-project.org, lars@metafoo.de, Stephen Warren,
s.hauer@pengutronix.de, tomasz.figa@gmail.com,
rob.herring@calxeda.com, p.zabel@pengutronix.de,
shawn.guo@linaro.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130827145016.GW10783@sirena.org.uk>
Oh, I didn't mean to push this. Sorry that I wasn't aware of it.
I'll be more patient next time.
Best regards,
Nicolin Chen
________________________________________
From: Mark Brown [broonie@kernel.org]
Sent: Tuesday, August 27, 2013 10:50 PM
To: Chen Guangyu-B42378
Cc: Stephen Warren; mark.rutland@arm.com; devicetree@vger.kernel.org; alsa-=
devel@alsa-project.org; lars@metafoo.de; s.hauer@pengutronix.de; tomasz.fig=
a@gmail.com; rob.herring@calxeda.com; p.zabel@pengutronix.de; shawn.guo@lin=
aro.org; linuxppc-dev@lists.ozlabs.org
Subject: Re: [alsa-devel] [PATCH v11] ASoC: fsl: Add S/PDIF machine driver
On Tue, Aug 27, 2013 at 10:01:08AM +0800, Nicolin Chen wrote:
> On Fri, Aug 23, 2013 at 08:13:53PM +0100, Mark Brown wrote:
> I think this patch hasn't been applied yet, already been acked though.
> Is there any problem in it?
You've allowed less than one working day for a response here - Monday
was a holiday in the UK. Something like a week is normally a minimum
for this sort of thing, especially in a case like this where there has
been extensive discussion.
^ permalink raw reply
* Re: Build regressions/improvements in v3.11-rc7
From: Geert Uytterhoeven @ 2013-08-27 17:55 UTC (permalink / raw)
To: Linux Kernel Development; +Cc: Linux/PPC Development
In-Reply-To: <alpine.DEB.2.02.1308271951240.13016@ayla.of.borg>
On Tue, 27 Aug 2013, Geert Uytterhoeven wrote:
> JFYI, when comparing v3.11-rc7 to v3.11-rc6[3], the summaries are:
> - build errors: +15/-9
+ /scratch/kisskb/src/arch/powerpc/sysdev/mpic.c: error: case label does not reduce to an integer constant: => 892:9, 904:9, 900:9, 896:9
+ /scratch/kisskb/src/drivers/net/ethernet/amd/lance.c: error: implicit declaration of function 'isa_bus_to_virt' [-Werror=implicit-function-declaration]: => 1204:6
+ /scratch/kisskb/src/drivers/net/ethernet/amd/lance.c: error: implicit declaration of function 'isa_virt_to_bus' [-Werror=implicit-function-declaration]: => 575:2
+ /scratch/kisskb/src/drivers/net/ethernet/amd/ni65.c: error: implicit declaration of function 'isa_bus_to_virt' [-Werror=implicit-function-declaration]: => 756:4
+ /scratch/kisskb/src/drivers/net/ethernet/amd/ni65.c: error: implicit declaration of function 'isa_virt_to_bus' [-Werror=implicit-function-declaration]: => 586:2
+ /scratch/kisskb/src/drivers/net/ethernet/cirrus/cs89x0.c: error: implicit declaration of function 'isa_virt_to_bus' [-Werror=implicit-function-declaration]: => 896:1
+ /scratch/kisskb/src/drivers/scsi/aha1542.c: error: implicit declaration of function 'isa_page_to_bus' [-Werror=implicit-function-declaration]: => 674:4
+ /scratch/kisskb/src/drivers/scsi/aha1542.c: error: implicit declaration of function 'isa_virt_to_bus' [-Werror=implicit-function-declaration]: => 477:3
+ /scratch/kisskb/src/drivers/scsi/wd7000.c: error: implicit declaration of function 'isa_bus_to_virt' [-Werror=implicit-function-declaration]: => 1055:2
+ /scratch/kisskb/src/drivers/scsi/wd7000.c: error: implicit declaration of function 'isa_page_to_bus' [-Werror=implicit-function-declaration]: => 1121:4
+ error: No rule to make target drivers/scsi/aic7xxx/aicasm/*.[chyl]: => N/A
powerpc-randconfig
+ /scratch/kisskb/src/drivers/usb/host/ohci-pci.c: error: 'ohci_resume' undeclared (first use in this function): => 310:34
+ /scratch/kisskb/src/drivers/usb/host/ohci-pci.c: error: 'ohci_suspend' undeclared (first use in this function): => 309:35
20 configs suppressed ;-)
> [1] http://kisskb.ellerman.id.au/kisskb/head/6579/ (all 120 configs)
> [3] http://kisskb.ellerman.id.au/kisskb/head/6556/ (all 120 configs)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH V6 0/7] POWER/cpuidle: Generic IBM-POWER cpuidle driver enabled for PSERIES and POWERNV platforms
From: Deepthi Dharwar @ 2013-08-27 18:30 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
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
V5 -> http://lkml.org/lkml/2013/8/22/184
Changes in V6:
=============
* Made changes in Patch3: Generic POWER cpuidle driver in V5 by
breaking down to multiple patches, as there were multiple changes
including moving the file location.
* Remove MAX_IDLE_STATE macro and kernel command line for
IBM-POWER systems.
* Make backend driver a built-in, instead of a module.
As building this as a module is currently not possible.
* Generic backend driver minor cleanups.
* First two patches in V5 are not a part of the series, as
they are generic cleanups, already pushed into the tree.
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 (7):
pseries/cpuidle: Move processor_idle.c to drivers/cpuidle.
pseries/cpuidle: Use cpuidle_register() for initialisation.
pseries/cpuidle: Make pseries_idle backend driver a non-module.
pseries/cpuidle: Remove MAX_IDLE_STATE macro.
POWER/cpuidle: Generic POWER CPUIDLE driver supporting PSERIES.
POWER/cpuidle: Enable powernv cpuidle support.
powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
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/processor_idle.c | 360 -----------------------
drivers/cpuidle/Kconfig | 5
drivers/cpuidle/Kconfig.powerpc | 10 +
drivers/cpuidle/Makefile | 2
drivers/cpuidle/cpuidle-ibm-power.c | 316 ++++++++++++++++++++
9 files changed, 347 insertions(+), 372 deletions(-)
delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
create mode 100644 drivers/cpuidle/Kconfig.powerpc
create mode 100644 drivers/cpuidle/cpuidle-ibm-power.c
-- Deepthi
^ permalink raw reply
* [PATCH V6 1/7] pseries/cpuidle: Move processor_idle.c to drivers/cpuidle.
From: Deepthi Dharwar @ 2013-08-27 18:30 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.stgit@deepthi.in.ibm.com>
Move the file from arch specific pseries/processor_idle.c
to drivers/cpuidle/cpuidle-ibm-power.c
Make the relevant Makefile and Kconfig changes.
This will enable having a common backend cpuidle driver
for POWER platform going forward.
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 | 5
drivers/cpuidle/Kconfig.powerpc | 10 +
drivers/cpuidle/Makefile | 2
drivers/cpuidle/cpuidle-ibm-power.c | 360 +++++++++++++++++++++++
8 files changed, 378 insertions(+), 371 deletions(-)
delete mode 100644 arch/powerpc/platforms/pseries/processor_idle.c
create mode 100644 drivers/cpuidle/Kconfig.powerpc
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..50e1249 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -42,6 +42,11 @@ config CPU_IDLE_ZYNQ
help
Select this to enable cpuidle on Xilinx Zynq processors.
+menu "POWERPC CPU Idle Drivers"
+depends on PPC
+source "drivers/cpuidle/Kconfig.powerpc"
+endmenu
+
endif
config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
new file mode 100644
index 0000000..8f43dc2
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.powerpc
@@ -0,0 +1,10 @@
+#
+# POWERPC CPU Idle Drivers
+#
+config CPU_IDLE_IBM_POWER
+ bool "CPU Idle driver for IBM POWER platforms"
+ depends on PPC_PSERIES
+ default y
+ help
+ Select this option to enable processor idle state management
+ on IBM POWER platform.
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..c905b99
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -0,0 +1,360 @@
+/*
+ * 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");
^ permalink raw reply related
* [PATCH V6 2/7] pseries/cpuidle: Use cpuidle_register() for initialisation.
From: Deepthi Dharwar @ 2013-08-27 18:31 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.stgit@deepthi.in.ibm.com>
This patch replaces the cpuidle driver and devices initialisation
calls with a single generic cpuidle_register() call
and also includes minor refactoring of the code around it.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle-ibm-power.c | 80 +++++------------------------------
1 file changed, 12 insertions(+), 68 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index c905b99..b42b948 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -1,5 +1,5 @@
/*
- * processor_idle - idle state cpuidle driver.
+ * cpuidle-ibm-power - idle state cpuidle driver.
* Adapted from drivers/idle/intel_idle.c and
* drivers/acpi/processor_idle.c
*
@@ -28,7 +28,6 @@ struct cpuidle_driver pseries_idle_driver = {
#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)
@@ -52,13 +51,12 @@ static int snooze_loop(struct cpuidle_device *dev,
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)) {
+ while (!need_resched()) {
ppc64_runlatch_off();
HMT_low();
HMT_very_low();
@@ -187,7 +185,7 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
{
int hotcpu = (unsigned long)hcpu;
struct cpuidle_device *dev =
- per_cpu_ptr(pseries_cpuidle_devices, hotcpu);
+ per_cpu(cpuidle_devices, hotcpu);
if (dev && cpuidle_get_driver()) {
switch (action) {
@@ -244,50 +242,6 @@ static int pseries_cpuidle_driver_init(void)
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
@@ -295,9 +249,6 @@ static int pseries_idle_devices_init(void)
static int pseries_idle_probe(void)
{
- if (!firmware_has_feature(FW_FEATURE_SPLPAR))
- return -ENODEV;
-
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
@@ -306,10 +257,13 @@ static int pseries_idle_probe(void)
return -EPERM;
}
- if (get_lppaca()->shared_proc)
- cpuidle_state_table = shared_states;
- else
- cpuidle_state_table = dedicated_states;
+ 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;
}
@@ -323,22 +277,14 @@ static int __init pseries_processor_idle_init(void)
return retval;
pseries_cpuidle_driver_init();
- retval = cpuidle_register_driver(&pseries_idle_driver);
+ retval = cpuidle_register(&pseries_idle_driver, NULL);
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;
}
@@ -346,9 +292,7 @@ static void __exit pseries_processor_idle_exit(void)
{
unregister_cpu_notifier(&setup_hotplug_notifier);
- pseries_idle_devices_uninit();
- cpuidle_unregister_driver(&pseries_idle_driver);
-
+ cpuidle_unregister(&pseries_idle_driver);
return;
}
^ permalink raw reply related
* [PATCH V6 3/7] pseries/cpuidle: Make pseries_idle backend driver a non-module.
From: Deepthi Dharwar @ 2013-08-27 18:31 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.stgit@deepthi.in.ibm.com>
Currently pseries_idle cpuidle backend driver cannot be
built as a module due to dependencies. Therefore the driver has
to be built in. The dependency is around update_snooze_delay() defined
in cpuidle driver and called from kernel/sysfs.c.
This patch is removes all the module related code.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle-ibm-power.c | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index b42b948..262db3c 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -288,17 +288,4 @@ static int __init pseries_processor_idle_init(void)
return 0;
}
-static void __exit pseries_processor_idle_exit(void)
-{
-
- unregister_cpu_notifier(&setup_hotplug_notifier);
- cpuidle_unregister(&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");
+device_initcall(pseries_processor_idle_init);
^ permalink raw reply related
* [PATCH V6 4/7] pseries/cpuidle: Remove MAX_IDLE_STATE macro.
From: Deepthi Dharwar @ 2013-08-27 18:31 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.stgit@deepthi.in.ibm.com>
This patch removes the usage of MAX_IDLE_STATE macro
and dead code around it. The number of states
are determined at run time based on the cpuidle
state table selected on a given platform
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle-ibm-power.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index 262db3c..14ebdb4 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -25,9 +25,7 @@ struct cpuidle_driver pseries_idle_driver = {
.owner = THIS_MODULE,
};
-#define MAX_IDLE_STATE_COUNT 2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static int max_idle_state;
static struct cpuidle_state *cpuidle_state_table;
static inline void idle_loop_prolog(unsigned long *in_purr)
@@ -133,7 +131,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
/*
* States for dedicated partition case.
*/
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state dedicated_states[] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
@@ -153,7 +151,7 @@ static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
/*
* States for shared partition case.
*/
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state shared_states[] = {
{ /* Shared Cede */
.name = "Shared Cede",
.desc = "Shared Cede",
@@ -223,11 +221,7 @@ static int pseries_cpuidle_driver_init(void)
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;
+ for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
/* is the state not enabled? */
if (cpuidle_state_table[idle_state].enter == NULL)
@@ -252,16 +246,14 @@ static int pseries_idle_probe(void)
if (cpuidle_disable != IDLE_NO_OVERRIDE)
return -ENODEV;
- if (max_idle_state == 0) {
- printk(KERN_DEBUG "pseries processor idle disabled.\n");
- return -EPERM;
- }
-
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
- if (get_lppaca()->shared_proc)
+ if (get_lppaca()->shared_proc) {
cpuidle_state_table = shared_states;
- else
+ max_idle_state = ARRAY_SIZE(shared_states);
+ } else {
cpuidle_state_table = dedicated_states;
+ max_idle_state = ARRAY_SIZE(dedicated_states);
+ }
} else
return -ENODEV;
^ permalink raw reply related
* [PATCH V6 5/7] POWER/cpuidle: Generic POWER CPUIDLE driver supporting PSERIES.
From: Deepthi Dharwar @ 2013-08-27 18:31 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.stgit@deepthi.in.ibm.com>
This patch includes cleanup and refactoring of the
existing code to make the driver POWER generic.
* Re-naming the functions from pseries to generic power.
* Re-naming the backend driver from pseries_idle to
ibm-power-idle.
Signed-off-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com>
---
drivers/cpuidle/cpuidle-ibm-power.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index 14ebdb4..162deda 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -20,8 +20,8 @@
#include <asm/runlatch.h>
#include <asm/plpar_wrappers.h>
-struct cpuidle_driver pseries_idle_driver = {
- .name = "pseries_idle",
+struct cpuidle_driver power_idle_driver = {
+ .name = "ibm_power_idle",
.owner = THIS_MODULE,
};
@@ -178,7 +178,7 @@ void update_smt_snooze_delay(int cpu, int residency)
drv->states[1].target_residency = residency;
}
-static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
+static int power_cpuidle_add_cpu_notifier(struct notifier_block *n,
unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
@@ -209,16 +209,16 @@ static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
}
static struct notifier_block setup_hotplug_notifier = {
- .notifier_call = pseries_cpuidle_add_cpu_notifier,
+ .notifier_call = power_cpuidle_add_cpu_notifier,
};
/*
- * pseries_cpuidle_driver_init()
+ * power_cpuidle_driver_init()
*/
-static int pseries_cpuidle_driver_init(void)
+static int power_cpuidle_driver_init(void)
{
int idle_state;
- struct cpuidle_driver *drv = &pseries_idle_driver;
+ struct cpuidle_driver *drv = &power_idle_driver;
drv->state_count = 0;
for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
@@ -237,10 +237,10 @@ static int pseries_cpuidle_driver_init(void)
}
/*
- * pseries_idle_probe()
+ * power_idle_probe()
* Choose state table for shared versus dedicated partition
*/
-static int pseries_idle_probe(void)
+static int power_idle_probe(void)
{
if (cpuidle_disable != IDLE_NO_OVERRIDE)
@@ -260,24 +260,24 @@ static int pseries_idle_probe(void)
return 0;
}
-static int __init pseries_processor_idle_init(void)
+static int __init power_processor_idle_init(void)
{
int retval;
- retval = pseries_idle_probe();
+ retval = power_idle_probe();
if (retval)
return retval;
- pseries_cpuidle_driver_init();
- retval = cpuidle_register(&pseries_idle_driver, NULL);
+ power_cpuidle_driver_init();
+ retval = cpuidle_register(&power_idle_driver, NULL);
if (retval) {
- printk(KERN_DEBUG "Registration of pseries driver failed.\n");
+ printk(KERN_DEBUG "Registration of ibm_power_idle driver failed.\n");
return retval;
}
register_cpu_notifier(&setup_hotplug_notifier);
- printk(KERN_DEBUG "pseries_idle_driver registered\n");
+ printk(KERN_DEBUG "ibm_power_idle registered\n");
return 0;
}
-device_initcall(pseries_processor_idle_init);
+device_initcall(power_processor_idle_init);
^ permalink raw reply related
* [PATCH V6 6/7] POWER/cpuidle: Enable powernv cpuidle support.
From: Deepthi Dharwar @ 2013-08-27 18:31 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.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 | 39 ++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/drivers/cpuidle/cpuidle-ibm-power.c b/drivers/cpuidle/cpuidle-ibm-power.c
index 162deda..f8905c3 100644
--- a/drivers/cpuidle/cpuidle-ibm-power.c
+++ b/drivers/cpuidle/cpuidle-ibm-power.c
@@ -48,9 +48,10 @@ static int snooze_loop(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- unsigned long in_purr;
+ unsigned long in_purr = 0;
- idle_loop_prolog(&in_purr);
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
+ idle_loop_prolog(&in_purr);
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
@@ -64,7 +65,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;
}
@@ -128,6 +130,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.
*/
@@ -161,6 +172,23 @@ static struct cpuidle_state shared_states[] = {
.enter = &shared_cede_loop },
};
+static struct cpuidle_state powernv_states[] = {
+ { /* 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();
@@ -254,6 +282,11 @@ static int power_idle_probe(void)
cpuidle_state_table = dedicated_states;
max_idle_state = ARRAY_SIZE(dedicated_states);
}
+
+ } else if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+ cpuidle_state_table = powernv_states;
+ max_idle_state = ARRAY_SIZE(powernv_states);
+
} else
return -ENODEV;
^ permalink raw reply related
* [PATCH V6 7/7] powernv/cpuidle: Enable idle powernv cpu to call into the cpuidle framework.
From: Deepthi Dharwar @ 2013-08-27 18:32 UTC (permalink / raw)
To: linux-pm, linuxppc-dev, linux-kernel
Cc: b.zolnierkie, daniel.lezcano, dongsheng.wang, preeti,
srivatsa.bhat, scottwood
In-Reply-To: <20130827183016.18579.16595.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] ppc: bpf_jit: support MOD operation
From: Vladimir Murzin @ 2013-08-27 22:49 UTC (permalink / raw)
To: linuxppc-dev; +Cc: dborkman, paulus, davem, Vladimir Murzin
commit b6069a9570 (filter: add MOD operation) added generic
support for modulus operation in BPF.
This patch brings JIT support for PPC64
Signed-off-by: Vladimir Murzin <murzin.v@gmail.com>
---
arch/powerpc/net/bpf_jit_comp.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index bf56e33..96f24dc 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -193,6 +193,28 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
PPC_MUL(r_A, r_A, r_scratch1);
}
break;
+ case BPF_S_ALU_MOD_X: /* A %= X; */
+ ctx->seen |= SEEN_XREG;
+ PPC_CMPWI(r_X, 0);
+ if (ctx->pc_ret0 != -1) {
+ PPC_BCC(COND_EQ, addrs[ctx->pc_ret0]);
+ } else {
+ PPC_BCC_SHORT(COND_NE, (ctx->idx*4)+12);
+ PPC_LI(r_ret, 0);
+ PPC_JMP(exit_addr);
+ }
+ PPC_DIVWU(r_scratch1, r_A, r_X);
+ PPC_MUL(r_scratch1, r_X, r_scratch1);
+ PPC_SUB(r_A, r_A, r_scratch1);
+ break;
+ case BPF_S_ALU_MOD_K: /* A %= K; */
+#define r_scratch2 (r_scratch1 + 1)
+ PPC_LI32(r_scratch2, K);
+ PPC_DIVWU(r_scratch1, r_A, r_scratch2);
+ PPC_MUL(r_scratch1, r_scratch2, r_scratch1);
+ PPC_SUB(r_A, r_A, r_scratch1);
+#undef r_scratch2
+ break;
case BPF_S_ALU_DIV_X: /* A /= X; */
ctx->seen |= SEEN_XREG;
PPC_CMPWI(r_X, 0);
--
1.8.1.5
^ permalink raw reply related
* Re: Critical Interrupt Input
From: Henry Bausley @ 2013-08-27 22:11 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1377040129.25016.181.camel@pasglop>
Both methods you described seem to work. We are currently using the
method of clearing the partially written TLB. Seems to be working but
we're still testing. Thanks.=20=20
=2E
=2E
=2E
mfspr r5,SPRN_CSRR0;
lis r12,finish_tlb_load_44x@h
ori r12,r12,finish_tlb_load_44x@l;
addi r11,r12,finish_tlb_load_44x_end-finish_tlb_load_44x;
cmplw cr0,r5,r12;
cmplw cr1,r5,r11;
ble cr0,3f;
bge cr1,3f;
li r12,0;
mr r5,r11
tlbwe r12,r13,PPC44x_TLB_XLAT;
tlbwe r12,r13,PPC44x_TLB_PAGEID; /* Clear PAGEID */
tlbwe r12,r13,PPC44x_TLB_ATTRIB; /* Clear ATTRIB */
isync
=2E
=2E
=2E
On Wed, 2013-08-21 at 09:08 +1000, Benjamin Herrenschmidt wrote:
> On Tue, 2013-08-20 at 15:48 -0700, Henry Bausley wrote:
> > Ben,
> >=20
> >=20
> > After your hints I suspected the read of a real world i/o variable *piom
> > which came from ioremap_nocache in the 3 line critical interrupt handler
> >=20
> > void critintr_handler(void *dev)
> > {
> > critintrcount++; // increment a variable
> > iodata =3D *piom; // read an I/O location=20
> > mtdcr(0x0c0, 0x00002000); // clear critical interrupt=20
> > }=20
> >=20
> > is what caused the problem. Commenting it out seems to make the system =
stable.=20=20
>=20
> Right, definitely would do that. BTW. You may want to use proper IO
> accessors while at it, to get the right memory barriers etc...
>=20
> > This led us to disable the critical interrupt when in the
> > DataTLBError44x and InstructionTLBError44x exceptions. Now the critical
> > interrupt handler seems to make things more stable when reading real
> > world i/o for our application.
> >
> >=20
> > /* Data TLB Error Interrupt */
> > START_EXCEPTION(DataTLBError44x)
> > mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working */
> > + mfmsr r10 /* Disable the */
> > + rlwinm r10,r10,0,15,13 /* MSR's CE bit */
> > + mtmsr r10=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=
=20=20
> >=20
> >=20
> > Do you see any potential problems with this approach?
> >=20
> > If so can you advise us on how to better take care of this.
>=20
> - You potentially still have an exposure ... between the mtspr to
> scratch and the mfmsr, a CRIC can occur, causing a re-entrancy which
> would than clobber the scratch register. That can be handled by saving
> that scratc SPRG into the stack frame on entry/exit from the crit
> interrupt. Look at crit_transfer_to_handler, how it already handles
> MMUCR:
>=20
> mfspr r0,SPRN_MMUCR
> stw r0,MMUCR(r11)
>=20
> Probably add saving of the SPRG_WSCRATCH0 in there (need to add a frame
> slot for it) and do the restore in RESTORE_MMU_REGS
>=20
> - You need to handle Instructions TLB miss as well
>=20
> - You add overhead to the TLB miss handlers which are fairly
> performance critical pieces of code. You might be able to alleviate
> that by making the whole thing support re-entrancy properly but that's
> harder. To do that you would have to:
>=20
> * Save *all* the SPRGs used by the TLB miss during crit entry/exit
>=20
> * Detect in crit_transfer_to_handler (check the CSRR0 bounds) that=20
> the crit code interrupted finish_tlb_load_44x before or at the
> last tlbwe instruction. In that case, immediately clear the=20
> partially written TLB entry (index in r13) and change the
> return address to skip right past the last tlbwe.
>=20
> Cheers,
> Ben.
>=20
>=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> > On Tue, 2013-08-20 at 06:56 +1000, Benjamin Herrenschmidt wrote:
> > > On Mon, 2013-08-19 at 12:00 -0700, Henry Bausley wrote:
> > > >=20
> > > > Support does appear to be present but there is a problem returning
> > > > back to user space I suspect.
> > >=20
> > > Probably a problem with TLB misses vs. crit interrupts.
> > >=20
> > > A critical interrupt can re-enter a TLB miss.
> > >=20
> > > I can see two potential issues there:
> > >=20
> > > - A bug where we don't properly restore "something" (I thought we did
> > > save and restore MMUCR though, but that's worth dbl checking if it wo=
rks
> > > properly) accross the crit entry/exit
> > >=20
> > > - Something in your crit code causing a TLB miss (the
> > > kernel .text/.data/.bss should be bolted but anything else can). We
> > > don't currently support re-entering the TLB miss that way.
> > >=20
> > > If we were to support the latter, we'd need to detect on entering a c=
rit
> > > that the PC is within the TLB miss handler, and setup a return context
> > > to the original instruction (replay the miss) rather than trying to
> > > resume it..
> > >=20
> > > Cheers,
> > > Ben.
> > >=20
> > > > What fails is it causes Linux user space programs to get Segmentati=
on
> > > > errors.
> > > > Issuing a simple ls causes a segmentation fault sometimes. The she=
ll
> > > > gets terminated=20
> > > > and you cannot log back in. INIT: Id "T0" respawning too fast:
> > > > disabled for 5 minutes pops up.
> > > >=20
> > > > However, the critical interrupt handler keeps running. I know this=
by
> > > > adding the reading=20
> > > > of a physical I/O location in the handler and can see it is being r=
ead
> > > > on the scope.
> > > >=20
> > > >=20
> > > > The only code in the handler is below.
> > > >=20
> > > > void critintr_handler(void *dev)
> > > > {
> > > > critintrcount++; // increment a variable
> > > > iodata =3D *piom; // read an I/O location=20
> > > > mtdcr(0x0c0, 0x00002000); // clear critical interrupt
> > > > }
> > > >=20
> > > >=20
> > > > Below is a log of the type of crashes that occur:
> > > >=20
> > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > Segmentation fault
> > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > Segmentation fault
> > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > Makefile ktest.c ktest.ko ktest.mod.o modules.order
> > > > Module.symvers ktest.cbp ktest.mod.c ktest.o
> > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > >=20
> > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > >=20
> > > > powerpmac login: root
> > > >=20
> > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > >=20
> > > > powerpmac login: root
> > > >=20
> > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > >=20
> > > > powerpmac login: root
> > > >=20
> > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > >=20
> > > > powerpmac login: root
> > > > Password:=20
> > > > Last login: Thu Nov 30 20:42:16 UTC 1933 on ttyS0
> > > > Linux powerpmac 3.2.21-aspen_2.01.09 #10 Mon Aug 19 08:49:12 PDT 20=
13
> > > > ppc
> > > >=20
> > > > The programs included with the Debian GNU/Linux system are free
> > > > software;
> > > > the exact distribution terms for each program are described in the
> > > > individual files in /usr/share/doc/*/copyright.
> > > >=20
> > > > Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
> > > > permitted by applicable law.
> > > > INIT: Id "T0" respawning too fast: disabled for 5 minutes
> > > >=20
> > > >=20
> > > > ___________________________________________________________________=
___
> > > > From: "Benjamin Herrenschmidt" <benh@kernel.crashing.org>
> > > > Sent: Saturday, August 17, 2013 3:05 PM
> > > > To: "Kumar Gala" <galak@kernel.crashing.org>
> > > > Cc: linuxppc-dev@lists.ozlabs.org, hbausley@deltatau.com
> > > > Subject: Re: Critical Interrupt Input
> > > >=20
> > > > On Fri, 2013-08-16 at 06:04 -0500, Kumar Gala wrote:
> > > > > The 44x low level code needs to handle exception stacks properly =
for
> > > > > this to work. Since its possible to have a critical exception occ=
ur
> > > > > while in a normal exception level, you have to have proper saving=
of
> > > > > additional register state and a stack frame for the critical
> > > > > exception, etc. I'm not sure if that was ever done for 44x.
> > > >=20
> > > > Don't 44x and FSL BookE share the same macros ? I would think 44x d=
oes
> > > > indeed implement the same crit support as e500...
> > > >=20
> > > > What does the crash look like ?
> > > >=20
> > > > Ben.
> > > >=20
> > > >=20
> > > > _______________________________________________
> > > > Linuxppc-dev mailing list
> > > > Linuxppc-dev@lists.ozlabs.org
> > > > https://lists.ozlabs.org/listinfo/linuxppc-dev
> > > >=20
> > > >=20
> > > > =C2=AD=C2=AD=20=20
> > >=20
> > >=20
> >=20
> >=20
> >=20
> >=20
> >=20
> > Outbound scan for Spam or Virus by Barracuda at Delta Tau
>=20
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: Critical Interrupt Input
From: Benjamin Herrenschmidt @ 2013-08-27 22:14 UTC (permalink / raw)
To: Henry Bausley; +Cc: linuxppc-dev
In-Reply-To: <1377641516.4691.11.camel@lx-henry>
On Tue, 2013-08-27 at 15:11 -0700, Henry Bausley wrote:
> Both methods you described seem to work. We are currently using the
> method of clearing the partially written TLB. Seems to be working but
> we're still testing. Thanks.
Feel free to send me us patch for review :-)
Cheers,
Ben.
> .
> .
> .
> mfspr r5,SPRN_CSRR0;
> lis r12,finish_tlb_load_44x@h
> ori r12,r12,finish_tlb_load_44x@l;
> addi r11,r12,finish_tlb_load_44x_end-finish_tlb_load_44x;
> cmplw cr0,r5,r12;
> cmplw cr1,r5,r11;
> ble cr0,3f;
> bge cr1,3f;
> li r12,0;
> mr r5,r11
> tlbwe r12,r13,PPC44x_TLB_XLAT;
> tlbwe r12,r13,PPC44x_TLB_PAGEID; /* Clear PAGEID */
> tlbwe r12,r13,PPC44x_TLB_ATTRIB; /* Clear ATTRIB */
> isync
> .
> .
> .
>
>
> On Wed, 2013-08-21 at 09:08 +1000, Benjamin Herrenschmidt wrote:
> > On Tue, 2013-08-20 at 15:48 -0700, Henry Bausley wrote:
> > > Ben,
> > >
> > >
> > > After your hints I suspected the read of a real world i/o variable *piom
> > > which came from ioremap_nocache in the 3 line critical interrupt handler
> > >
> > > void critintr_handler(void *dev)
> > > {
> > > critintrcount++; // increment a variable
> > > iodata = *piom; // read an I/O location
> > > mtdcr(0x0c0, 0x00002000); // clear critical interrupt
> > > }
> > >
> > > is what caused the problem. Commenting it out seems to make the system stable.
> >
> > Right, definitely would do that. BTW. You may want to use proper IO
> > accessors while at it, to get the right memory barriers etc...
> >
> > > This led us to disable the critical interrupt when in the
> > > DataTLBError44x and InstructionTLBError44x exceptions. Now the critical
> > > interrupt handler seems to make things more stable when reading real
> > > world i/o for our application.
> > >
> > >
> > > /* Data TLB Error Interrupt */
> > > START_EXCEPTION(DataTLBError44x)
> > > mtspr SPRN_SPRG_WSCRATCH0, r10 /* Save some working */
> > > + mfmsr r10 /* Disable the */
> > > + rlwinm r10,r10,0,15,13 /* MSR's CE bit */
> > > + mtmsr r10
> > >
> > >
> > > Do you see any potential problems with this approach?
> > >
> > > If so can you advise us on how to better take care of this.
> >
> > - You potentially still have an exposure ... between the mtspr to
> > scratch and the mfmsr, a CRIC can occur, causing a re-entrancy which
> > would than clobber the scratch register. That can be handled by saving
> > that scratc SPRG into the stack frame on entry/exit from the crit
> > interrupt. Look at crit_transfer_to_handler, how it already handles
> > MMUCR:
> >
> > mfspr r0,SPRN_MMUCR
> > stw r0,MMUCR(r11)
> >
> > Probably add saving of the SPRG_WSCRATCH0 in there (need to add a frame
> > slot for it) and do the restore in RESTORE_MMU_REGS
> >
> > - You need to handle Instructions TLB miss as well
> >
> > - You add overhead to the TLB miss handlers which are fairly
> > performance critical pieces of code. You might be able to alleviate
> > that by making the whole thing support re-entrancy properly but that's
> > harder. To do that you would have to:
> >
> > * Save *all* the SPRGs used by the TLB miss during crit entry/exit
> >
> > * Detect in crit_transfer_to_handler (check the CSRR0 bounds) that
> > the crit code interrupted finish_tlb_load_44x before or at the
> > last tlbwe instruction. In that case, immediately clear the
> > partially written TLB entry (index in r13) and change the
> > return address to skip right past the last tlbwe.
> >
> > Cheers,
> > Ben.
> >
> >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > >
> > > On Tue, 2013-08-20 at 06:56 +1000, Benjamin Herrenschmidt wrote:
> > > > On Mon, 2013-08-19 at 12:00 -0700, Henry Bausley wrote:
> > > > >
> > > > > Support does appear to be present but there is a problem returning
> > > > > back to user space I suspect.
> > > >
> > > > Probably a problem with TLB misses vs. crit interrupts.
> > > >
> > > > A critical interrupt can re-enter a TLB miss.
> > > >
> > > > I can see two potential issues there:
> > > >
> > > > - A bug where we don't properly restore "something" (I thought we did
> > > > save and restore MMUCR though, but that's worth dbl checking if it works
> > > > properly) accross the crit entry/exit
> > > >
> > > > - Something in your crit code causing a TLB miss (the
> > > > kernel .text/.data/.bss should be bolted but anything else can). We
> > > > don't currently support re-entering the TLB miss that way.
> > > >
> > > > If we were to support the latter, we'd need to detect on entering a crit
> > > > that the PC is within the TLB miss handler, and setup a return context
> > > > to the original instruction (replay the miss) rather than trying to
> > > > resume it..
> > > >
> > > > Cheers,
> > > > Ben.
> > > >
> > > > > What fails is it causes Linux user space programs to get Segmentation
> > > > > errors.
> > > > > Issuing a simple ls causes a segmentation fault sometimes. The shell
> > > > > gets terminated
> > > > > and you cannot log back in. INIT: Id "T0" respawning too fast:
> > > > > disabled for 5 minutes pops up.
> > > > >
> > > > > However, the critical interrupt handler keeps running. I know this by
> > > > > adding the reading
> > > > > of a physical I/O location in the handler and can see it is being read
> > > > > on the scope.
> > > > >
> > > > >
> > > > > The only code in the handler is below.
> > > > >
> > > > > void critintr_handler(void *dev)
> > > > > {
> > > > > critintrcount++; // increment a variable
> > > > > iodata = *piom; // read an I/O location
> > > > > mtdcr(0x0c0, 0x00002000); // clear critical interrupt
> > > > > }
> > > > >
> > > > >
> > > > > Below is a log of the type of crashes that occur:
> > > > >
> > > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > > Segmentation fault
> > > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > > Segmentation fault
> > > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > > Makefile ktest.c ktest.ko ktest.mod.o modules.order
> > > > > Module.symvers ktest.cbp ktest.mod.c ktest.o
> > > > > root@10.34.9.213:/opt/ppmac/ktest# ls
> > > > >
> > > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > > >
> > > > > powerpmac login: root
> > > > >
> > > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > > >
> > > > > powerpmac login: root
> > > > >
> > > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > > >
> > > > > powerpmac login: root
> > > > >
> > > > > Debian GNU/Linux 7 powerpmac ttyS0
> > > > >
> > > > > powerpmac login: root
> > > > > Password:
> > > > > Last login: Thu Nov 30 20:42:16 UTC 1933 on ttyS0
> > > > > Linux powerpmac 3.2.21-aspen_2.01.09 #10 Mon Aug 19 08:49:12 PDT 2013
> > > > > ppc
> > > > >
> > > > > The programs included with the Debian GNU/Linux system are free
> > > > > software;
> > > > > the exact distribution terms for each program are described in the
> > > > > individual files in /usr/share/doc/*/copyright.
> > > > >
> > > > > Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
> > > > > permitted by applicable law.
> > > > > INIT: Id "T0" respawning too fast: disabled for 5 minutes
> > > > >
> > > > >
> > > > > ______________________________________________________________________
> > > > > From: "Benjamin Herrenschmidt" <benh@kernel.crashing.org>
> > > > > Sent: Saturday, August 17, 2013 3:05 PM
> > > > > To: "Kumar Gala" <galak@kernel.crashing.org>
> > > > > Cc: linuxppc-dev@lists.ozlabs.org, hbausley@deltatau.com
> > > > > Subject: Re: Critical Interrupt Input
> > > > >
> > > > > On Fri, 2013-08-16 at 06:04 -0500, Kumar Gala wrote:
> > > > > > The 44x low level code needs to handle exception stacks properly for
> > > > > > this to work. Since its possible to have a critical exception occur
> > > > > > while in a normal exception level, you have to have proper saving of
> > > > > > additional register state and a stack frame for the critical
> > > > > > exception, etc. I'm not sure if that was ever done for 44x.
> > > > >
> > > > > Don't 44x and FSL BookE share the same macros ? I would think 44x does
> > > > > indeed implement the same crit support as e500...
> > > > >
> > > > > What does the crash look like ?
> > > > >
> > > > > Ben.
> > > > >
> > > > >
> > > > > _______________________________________________
> > > > > Linuxppc-dev mailing list
> > > > > Linuxppc-dev@lists.ozlabs.org
> > > > > https://lists.ozlabs.org/listinfo/linuxppc-dev
> > > > >
> > > > >
> > > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> > >
> > > Outbound scan for Spam or Virus by Barracuda at Delta Tau
> >
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
>
>
^ permalink raw reply
* Re: [PATCH v8] KVM: PPC: reserve a capability and ioctl numbers for realmode VFIO
From: Alexey Kardashevskiy @ 2013-08-28 0:51 UTC (permalink / raw)
To: Gleb Natapov
Cc: kvm, Alexander Graf, linux-kernel, Paul Mackerras, linuxppc-dev,
David Gibson
In-Reply-To: <20130827105832.GH22899@redhat.com>
On 08/27/2013 08:58 PM, Gleb Natapov wrote:
> On Tue, Aug 27, 2013 at 06:42:18PM +1000, Alexey Kardashevskiy wrote:
>> On 08/27/2013 05:56 PM, Gleb Natapov wrote:
>>> On Thu, Aug 15, 2013 at 05:49:26PM +1000, Alexey Kardashevskiy wrote:
>>>> This is to reserve a capablity number for upcoming support
>>>> of VFIO-IOMMU DMA operations in real mode.
>>>>
>>>> The last ioctl in the group which KVM_CREATE_SPAPR_TCE_IOMMU is added to
>>>> is 0xac, the next two numbers are taken - 0xad for KVM_KVMCLOCK_CTRL and
>>> 0xac was also taken by KVM_SET_ONE_REG :(
>>>
>>>> 0xae for KVM_ARM_VCPU_INIT. So the KVM_CREATE_SPAPR_TCE_IOMMU ioclt gets
>>>> 0xaf.
>>>>
>>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>>>
>>>> ---
>>>> Changes:
>>>> 2013/08/15 v8:
>>>> * fixed comment again
>>>>
>>>> 2013/08/15:
>>>> * fixed mistype in comments
>>>> * fixed commit message which says what uses ioctls 0xad and 0xae
>>>>
>>>> 2013/07/16:
>>>> * changed the number
>>>>
>>>> 2013/07/11:
>>>> * changed order in a file, added comment about a gap in ioctl number
>>>> ---
>>>> include/uapi/linux/kvm.h | 6 ++++++
>>>> 1 file changed, 6 insertions(+)
>>>>
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 99c2533..bd94127 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -668,6 +668,7 @@ struct kvm_ppc_smmu_info {
>>>> #define KVM_CAP_IRQ_XICS 92
>>>> #define KVM_CAP_ARM_EL1_32BIT 93
>>>> #define KVM_CAP_SPAPR_MULTITCE 94
>>>> +#define KVM_CAP_SPAPR_TCE_IOMMU 95
>>>>
>>>> #ifdef KVM_CAP_IRQ_ROUTING
>>>>
>>>> @@ -933,6 +934,11 @@ struct kvm_s390_ucas_mapping {
>>>> #define KVM_ARM_SET_DEVICE_ADDR _IOW(KVMIO, 0xab, struct kvm_arm_device_addr)
>>>> /* Available with KVM_CAP_PPC_RTAS */
>>>> #define KVM_PPC_RTAS_DEFINE_TOKEN _IOW(KVMIO, 0xac, struct kvm_rtas_token_args)
>>>> +/* 0xad is taken by KVM_KVMCLOCK_CTRL */
>>>> +/* 0xae is taken by KVM_ARM_VCPU_INIT */
>>>> +/* Available with KVM_CAP_SPAPR_TCE_IOMMU */
>>>> +#define KVM_CREATE_SPAPR_TCE_IOMMU _IOW(KVMIO, 0xaf, \
>>>> + struct kvm_create_spapr_tce_iommu)
>>>>
>>> Why not use KVM_CREATE_DEVICE API for that?
>>
>>
>> Because when I came up with my ioctl first time, it was not in upstream and
>> since then nobody pointed me to this new ioctl :)
> Sorry about that :(. The ioctl exists for a while now, but with v8 patch I
> imaging your patch series predates it.
The ioctl I made up is basically a copy of KVM_CREATE_SPAPR_TCE which does
the same thing for emulated devices and it is there for quite a while but
it is not really extensible. And these two ioctls share some bits of code.
Now we will have 2 pieces of code which do almost the same thing but in a
different way. Kinda sucks :(
>> So my stuff is not going to upstream again. Heh. Ok. I'll implement it.
>>
> Thanks! Should I keep KVM_CAP_SPAPR_MULTITCE capability patch or can I
> drop it for now?
Please keep it, it is unrelated to the IOMMU-VFIO thing.
--
Alexey
^ permalink raw reply
* Re: [PATCH v3 13/31] clk: wrap I/O access for improved portability
From: Mike Turquette @ 2013-08-28 0:55 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: Gerhard Sittig, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20130824000539.5554cad8@crub>
Quoting Anatolij Gustschin (2013-08-23 15:05:39)
> On Fri, 02 Aug 2013 15:30:00 -0700
> Mike Turquette <mturquette@linaro.org> wrote:
> =
> > Quoting Gerhard Sittig (2013-07-22 05:14:40)
> > > the common clock drivers were motivated/initiated by ARM development
> > > and apparently assume little endian peripherals
> > > =
> > > wrap register/peripherals access in the common code (div, gate, mux)
> > > in preparation of adding COMMON_CLK support for other platforms
> > > =
> > > Signed-off-by: Gerhard Sittig <gsi@denx.de>
> > =
> > I've taken this into clk-next for testing. regmap deserves investigation
> > but I don't think your series should be blocked on that. We can always
> > overhaul the basic clock primitives with regmap support later on if that
> > makes sense.
> =
> Mike, I cannot see it in clk-next branch of
> git://git.linaro.org/people/mturquette/linux.git
> =
> Can you please check? Or am I looking in the wrong place?
You were looking in the right place but I had not pushed out the latest
patches from my local branch. It should be there now.
Regards,
Mike
> =
> Thanks,
> Anatolij
^ permalink raw reply
* Re: [PATCH v8] KVM: PPC: reserve a capability and ioctl numbers for realmode VFIO
From: Benjamin Herrenschmidt @ 2013-08-28 1:26 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: Gleb Natapov, kvm, Alexander Graf, linux-kernel, Paul Mackerras,
linuxppc-dev, David Gibson
In-Reply-To: <521D4977.7060803@ozlabs.ru>
On Wed, 2013-08-28 at 10:51 +1000, Alexey Kardashevskiy wrote:
> The ioctl I made up is basically a copy of KVM_CREATE_SPAPR_TCE which does
> the same thing for emulated devices and it is there for quite a while but
> it is not really extensible. And these two ioctls share some bits of code.
> Now we will have 2 pieces of code which do almost the same thing but in a
> different way. Kinda sucks :(
Right. Thus the question, Gleb, we can either:
- Keep Alexey patch as-is allowing us to *finally* merge that stuff
that's been around for monthes
- Convert *both* existing TCE objects to the new
KVM_CREATE_DEVICE, and have some backward compat code for the old one.
I don't think it makes sense to have the "emulated TCE" and "IOMMU TCE"
objects use a fundamentally different API and infrastructure.
> >> So my stuff is not going to upstream again. Heh. Ok. I'll implement it.
> >>
> > Thanks! Should I keep KVM_CAP_SPAPR_MULTITCE capability patch or can I
> > drop it for now?
>
> Please keep it, it is unrelated to the IOMMU-VFIO thing.
^ permalink raw reply
* [PATCH] powerpc/pseries: Move lparcfg.c to platforms/pseries
From: Benjamin Herrenschmidt @ 2013-08-28 3:51 UTC (permalink / raw)
To: linuxppc-dev
This file is entirely pseries specific nowadays, so move it out
of arch/powerpc/kernel where it doesn't belong anymore.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/Makefile | 1 -
arch/powerpc/kernel/lparcfg.c | 710 -------------------------------
arch/powerpc/platforms/pseries/Makefile | 1 +
arch/powerpc/platforms/pseries/lparcfg.c | 710 +++++++++++++++++++++++++++++++
4 files changed, 711 insertions(+), 711 deletions(-)
delete mode 100644 arch/powerpc/kernel/lparcfg.c
create mode 100644 arch/powerpc/platforms/pseries/lparcfg.c
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 5b280f5..445cb6e 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -55,7 +55,6 @@ obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y)
obj-$(CONFIG_PPC_RTAS_DAEMON) += rtasd.o
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
-obj-$(CONFIG_LPARCFG) += lparcfg.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_IBMEBUS) += ibmebus.o
obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
deleted file mode 100644
index e738007..0000000
--- a/arch/powerpc/kernel/lparcfg.c
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
- * PowerPC64 LPAR Configuration Information Driver
- *
- * Dave Engebretsen engebret@us.ibm.com
- * Copyright (c) 2003 Dave Engebretsen
- * Will Schmidt willschm@us.ibm.com
- * SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation.
- * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation.
- * Nathan Lynch nathanl@austin.ibm.com
- * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * This driver creates a proc file at /proc/ppc64/lparcfg which contains
- * keyword - value pairs that specify the configuration of the partition.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-#include <asm/lppaca.h>
-#include <asm/hvcall.h>
-#include <asm/firmware.h>
-#include <asm/rtas.h>
-#include <asm/time.h>
-#include <asm/prom.h>
-#include <asm/vdso_datapage.h>
-#include <asm/vio.h>
-#include <asm/mmu.h>
-#include <asm/machdep.h>
-
-
-/*
- * This isn't a module but we expose that to userspace
- * via /proc so leave the definitions here
- */
-#define MODULE_VERS "1.9"
-#define MODULE_NAME "lparcfg"
-
-/* #define LPARCFG_DEBUG */
-
-/*
- * Track sum of all purrs across all processors. This is used to further
- * calculate usage values by different applications
- */
-static unsigned long get_purr(void)
-{
- unsigned long sum_purr = 0;
- int cpu;
-
- for_each_possible_cpu(cpu) {
- struct cpu_usage *cu;
-
- cu = &per_cpu(cpu_usage_array, cpu);
- sum_purr += cu->current_tb;
- }
- return sum_purr;
-}
-
-/*
- * Methods used to fetch LPAR data when running on a pSeries platform.
- */
-
-struct hvcall_ppp_data {
- u64 entitlement;
- u64 unallocated_entitlement;
- u16 group_num;
- u16 pool_num;
- u8 capped;
- u8 weight;
- u8 unallocated_weight;
- u16 active_procs_in_pool;
- u16 active_system_procs;
- u16 phys_platform_procs;
- u32 max_proc_cap_avail;
- u32 entitled_proc_cap_avail;
-};
-
-/*
- * H_GET_PPP hcall returns info in 4 parms.
- * entitled_capacity,unallocated_capacity,
- * aggregation, resource_capability).
- *
- * R4 = Entitled Processor Capacity Percentage.
- * R5 = Unallocated Processor Capacity Percentage.
- * R6 (AABBCCDDEEFFGGHH).
- * XXXX - reserved (0)
- * XXXX - reserved (0)
- * XXXX - Group Number
- * XXXX - Pool Number.
- * R7 (IIJJKKLLMMNNOOPP).
- * XX - reserved. (0)
- * XX - bit 0-6 reserved (0). bit 7 is Capped indicator.
- * XX - variable processor Capacity Weight
- * XX - Unallocated Variable Processor Capacity Weight.
- * XXXX - Active processors in Physical Processor Pool.
- * XXXX - Processors active on platform.
- * R8 (QQQQRRRRRRSSSSSS). if ibm,partition-performance-parameters-level >= 1
- * XXXX - Physical platform procs allocated to virtualization.
- * XXXXXX - Max procs capacity % available to the partitions pool.
- * XXXXXX - Entitled procs capacity % available to the
- * partitions pool.
- */
-static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data)
-{
- unsigned long rc;
- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
-
- rc = plpar_hcall9(H_GET_PPP, retbuf);
-
- ppp_data->entitlement = retbuf[0];
- ppp_data->unallocated_entitlement = retbuf[1];
-
- ppp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
- ppp_data->pool_num = retbuf[2] & 0xffff;
-
- ppp_data->capped = (retbuf[3] >> 6 * 8) & 0x01;
- ppp_data->weight = (retbuf[3] >> 5 * 8) & 0xff;
- ppp_data->unallocated_weight = (retbuf[3] >> 4 * 8) & 0xff;
- ppp_data->active_procs_in_pool = (retbuf[3] >> 2 * 8) & 0xffff;
- ppp_data->active_system_procs = retbuf[3] & 0xffff;
-
- ppp_data->phys_platform_procs = retbuf[4] >> 6 * 8;
- ppp_data->max_proc_cap_avail = (retbuf[4] >> 3 * 8) & 0xffffff;
- ppp_data->entitled_proc_cap_avail = retbuf[4] & 0xffffff;
-
- return rc;
-}
-
-static unsigned h_pic(unsigned long *pool_idle_time,
- unsigned long *num_procs)
-{
- unsigned long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_PIC, retbuf);
-
- *pool_idle_time = retbuf[0];
- *num_procs = retbuf[1];
-
- return rc;
-}
-
-/*
- * parse_ppp_data
- * Parse out the data returned from h_get_ppp and h_pic
- */
-static void parse_ppp_data(struct seq_file *m)
-{
- struct hvcall_ppp_data ppp_data;
- struct device_node *root;
- const int *perf_level;
- int rc;
-
- rc = h_get_ppp(&ppp_data);
- if (rc)
- return;
-
- seq_printf(m, "partition_entitled_capacity=%lld\n",
- ppp_data.entitlement);
- seq_printf(m, "group=%d\n", ppp_data.group_num);
- seq_printf(m, "system_active_processors=%d\n",
- ppp_data.active_system_procs);
-
- /* pool related entries are appropriate for shared configs */
- if (lppaca_shared_proc(get_lppaca())) {
- unsigned long pool_idle_time, pool_procs;
-
- seq_printf(m, "pool=%d\n", ppp_data.pool_num);
-
- /* report pool_capacity in percentage */
- seq_printf(m, "pool_capacity=%d\n",
- ppp_data.active_procs_in_pool * 100);
-
- h_pic(&pool_idle_time, &pool_procs);
- seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time);
- seq_printf(m, "pool_num_procs=%ld\n", pool_procs);
- }
-
- seq_printf(m, "unallocated_capacity_weight=%d\n",
- ppp_data.unallocated_weight);
- seq_printf(m, "capacity_weight=%d\n", ppp_data.weight);
- seq_printf(m, "capped=%d\n", ppp_data.capped);
- seq_printf(m, "unallocated_capacity=%lld\n",
- ppp_data.unallocated_entitlement);
-
- /* The last bits of information returned from h_get_ppp are only
- * valid if the ibm,partition-performance-parameters-level
- * property is >= 1.
- */
- root = of_find_node_by_path("/");
- if (root) {
- perf_level = of_get_property(root,
- "ibm,partition-performance-parameters-level",
- NULL);
- if (perf_level && (*perf_level >= 1)) {
- seq_printf(m,
- "physical_procs_allocated_to_virtualization=%d\n",
- ppp_data.phys_platform_procs);
- seq_printf(m, "max_proc_capacity_available=%d\n",
- ppp_data.max_proc_cap_avail);
- seq_printf(m, "entitled_proc_capacity_available=%d\n",
- ppp_data.entitled_proc_cap_avail);
- }
-
- of_node_put(root);
- }
-}
-
-/**
- * parse_mpp_data
- * Parse out data returned from h_get_mpp
- */
-static void parse_mpp_data(struct seq_file *m)
-{
- struct hvcall_mpp_data mpp_data;
- int rc;
-
- rc = h_get_mpp(&mpp_data);
- if (rc)
- return;
-
- seq_printf(m, "entitled_memory=%ld\n", mpp_data.entitled_mem);
-
- if (mpp_data.mapped_mem != -1)
- seq_printf(m, "mapped_entitled_memory=%ld\n",
- mpp_data.mapped_mem);
-
- seq_printf(m, "entitled_memory_group_number=%d\n", mpp_data.group_num);
- seq_printf(m, "entitled_memory_pool_number=%d\n", mpp_data.pool_num);
-
- seq_printf(m, "entitled_memory_weight=%d\n", mpp_data.mem_weight);
- seq_printf(m, "unallocated_entitled_memory_weight=%d\n",
- mpp_data.unallocated_mem_weight);
- seq_printf(m, "unallocated_io_mapping_entitlement=%ld\n",
- mpp_data.unallocated_entitlement);
-
- if (mpp_data.pool_size != -1)
- seq_printf(m, "entitled_memory_pool_size=%ld bytes\n",
- mpp_data.pool_size);
-
- seq_printf(m, "entitled_memory_loan_request=%ld\n",
- mpp_data.loan_request);
-
- seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
-}
-
-/**
- * parse_mpp_x_data
- * Parse out data returned from h_get_mpp_x
- */
-static void parse_mpp_x_data(struct seq_file *m)
-{
- struct hvcall_mpp_x_data mpp_x_data;
-
- if (!firmware_has_feature(FW_FEATURE_XCMO))
- return;
- if (h_get_mpp_x(&mpp_x_data))
- return;
-
- seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
-
- if (mpp_x_data.pool_coalesced_bytes)
- seq_printf(m, "pool_coalesced_bytes=%ld\n",
- mpp_x_data.pool_coalesced_bytes);
- if (mpp_x_data.pool_purr_cycles)
- seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
- if (mpp_x_data.pool_spurr_cycles)
- seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
-}
-
-#define SPLPAR_CHARACTERISTICS_TOKEN 20
-#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
-
-/*
- * parse_system_parameter_string()
- * Retrieve the potential_processors, max_entitled_capacity and friends
- * through the get-system-parameter rtas call. Replace keyword strings as
- * necessary.
- */
-static void parse_system_parameter_string(struct seq_file *m)
-{
- int call_status;
-
- unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
- if (!local_buffer) {
- printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
- __FILE__, __func__, __LINE__);
- return;
- }
-
- spin_lock(&rtas_data_buf_lock);
- memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
- call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
- NULL,
- SPLPAR_CHARACTERISTICS_TOKEN,
- __pa(rtas_data_buf),
- RTAS_DATA_BUF_SIZE);
- memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
- local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
- spin_unlock(&rtas_data_buf_lock);
-
- if (call_status != 0) {
- printk(KERN_INFO
- "%s %s Error calling get-system-parameter (0x%x)\n",
- __FILE__, __func__, call_status);
- } else {
- int splpar_strlen;
- int idx, w_idx;
- char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
- if (!workbuffer) {
- printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
- __FILE__, __func__, __LINE__);
- kfree(local_buffer);
- return;
- }
-#ifdef LPARCFG_DEBUG
- printk(KERN_INFO "success calling get-system-parameter\n");
-#endif
- splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
- local_buffer += 2; /* step over strlen value */
-
- w_idx = 0;
- idx = 0;
- while ((*local_buffer) && (idx < splpar_strlen)) {
- workbuffer[w_idx++] = local_buffer[idx++];
- if ((local_buffer[idx] == ',')
- || (local_buffer[idx] == '\0')) {
- workbuffer[w_idx] = '\0';
- if (w_idx) {
- /* avoid the empty string */
- seq_printf(m, "%s\n", workbuffer);
- }
- memset(workbuffer, 0, SPLPAR_MAXLENGTH);
- idx++; /* skip the comma */
- w_idx = 0;
- } else if (local_buffer[idx] == '=') {
- /* code here to replace workbuffer contents
- with different keyword strings */
- if (0 == strcmp(workbuffer, "MaxEntCap")) {
- strcpy(workbuffer,
- "partition_max_entitled_capacity");
- w_idx = strlen(workbuffer);
- }
- if (0 == strcmp(workbuffer, "MaxPlatProcs")) {
- strcpy(workbuffer,
- "system_potential_processors");
- w_idx = strlen(workbuffer);
- }
- }
- }
- kfree(workbuffer);
- local_buffer -= 2; /* back up over strlen value */
- }
- kfree(local_buffer);
-}
-
-/* Return the number of processors in the system.
- * This function reads through the device tree and counts
- * the virtual processors, this does not include threads.
- */
-static int lparcfg_count_active_processors(void)
-{
- struct device_node *cpus_dn = NULL;
- int count = 0;
-
- while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) {
-#ifdef LPARCFG_DEBUG
- printk(KERN_ERR "cpus_dn %p\n", cpus_dn);
-#endif
- count++;
- }
- return count;
-}
-
-static void pseries_cmo_data(struct seq_file *m)
-{
- int cpu;
- unsigned long cmo_faults = 0;
- unsigned long cmo_fault_time = 0;
-
- seq_printf(m, "cmo_enabled=%d\n", firmware_has_feature(FW_FEATURE_CMO));
-
- if (!firmware_has_feature(FW_FEATURE_CMO))
- return;
-
- for_each_possible_cpu(cpu) {
- cmo_faults += be64_to_cpu(lppaca_of(cpu).cmo_faults);
- cmo_fault_time += be64_to_cpu(lppaca_of(cpu).cmo_fault_time);
- }
-
- seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
- seq_printf(m, "cmo_fault_time_usec=%lu\n",
- cmo_fault_time / tb_ticks_per_usec);
- seq_printf(m, "cmo_primary_psp=%d\n", cmo_get_primary_psp());
- seq_printf(m, "cmo_secondary_psp=%d\n", cmo_get_secondary_psp());
- seq_printf(m, "cmo_page_size=%lu\n", cmo_get_page_size());
-}
-
-static void splpar_dispatch_data(struct seq_file *m)
-{
- int cpu;
- unsigned long dispatches = 0;
- unsigned long dispatch_dispersions = 0;
-
- for_each_possible_cpu(cpu) {
- dispatches += be32_to_cpu(lppaca_of(cpu).yield_count);
- dispatch_dispersions +=
- be32_to_cpu(lppaca_of(cpu).dispersion_count);
- }
-
- seq_printf(m, "dispatches=%lu\n", dispatches);
- seq_printf(m, "dispatch_dispersions=%lu\n", dispatch_dispersions);
-}
-
-static void parse_em_data(struct seq_file *m)
-{
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- if (firmware_has_feature(FW_FEATURE_LPAR) &&
- plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
- seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
-}
-
-static int pseries_lparcfg_data(struct seq_file *m, void *v)
-{
- int partition_potential_processors;
- int partition_active_processors;
- struct device_node *rtas_node;
- const int *lrdrp = NULL;
-
- rtas_node = of_find_node_by_path("/rtas");
- if (rtas_node)
- lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
-
- if (lrdrp == NULL) {
- partition_potential_processors = vdso_data->processorCount;
- } else {
- partition_potential_processors = *(lrdrp + 4);
- }
- of_node_put(rtas_node);
-
- partition_active_processors = lparcfg_count_active_processors();
-
- if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
- /* this call handles the ibm,get-system-parameter contents */
- parse_system_parameter_string(m);
- parse_ppp_data(m);
- parse_mpp_data(m);
- parse_mpp_x_data(m);
- pseries_cmo_data(m);
- splpar_dispatch_data(m);
-
- seq_printf(m, "purr=%ld\n", get_purr());
- } else { /* non SPLPAR case */
-
- seq_printf(m, "system_active_processors=%d\n",
- partition_potential_processors);
-
- seq_printf(m, "system_potential_processors=%d\n",
- partition_potential_processors);
-
- seq_printf(m, "partition_max_entitled_capacity=%d\n",
- partition_potential_processors * 100);
-
- seq_printf(m, "partition_entitled_capacity=%d\n",
- partition_active_processors * 100);
- }
-
- seq_printf(m, "partition_active_processors=%d\n",
- partition_active_processors);
-
- seq_printf(m, "partition_potential_processors=%d\n",
- partition_potential_processors);
-
- seq_printf(m, "shared_processor_mode=%d\n",
- lppaca_shared_proc(get_lppaca()));
-
- seq_printf(m, "slb_size=%d\n", mmu_slb_size);
-
- parse_em_data(m);
-
- return 0;
-}
-
-static ssize_t update_ppp(u64 *entitlement, u8 *weight)
-{
- struct hvcall_ppp_data ppp_data;
- u8 new_weight;
- u64 new_entitled;
- ssize_t retval;
-
- /* Get our current parameters */
- retval = h_get_ppp(&ppp_data);
- if (retval)
- return retval;
-
- if (entitlement) {
- new_weight = ppp_data.weight;
- new_entitled = *entitlement;
- } else if (weight) {
- new_weight = *weight;
- new_entitled = ppp_data.entitlement;
- } else
- return -EINVAL;
-
- pr_debug("%s: current_entitled = %llu, current_weight = %u\n",
- __func__, ppp_data.entitlement, ppp_data.weight);
-
- pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
- __func__, new_entitled, new_weight);
-
- retval = plpar_hcall_norets(H_SET_PPP, new_entitled, new_weight);
- return retval;
-}
-
-/**
- * update_mpp
- *
- * Update the memory entitlement and weight for the partition. Caller must
- * specify either a new entitlement or weight, not both, to be updated
- * since the h_set_mpp call takes both entitlement and weight as parameters.
- */
-static ssize_t update_mpp(u64 *entitlement, u8 *weight)
-{
- struct hvcall_mpp_data mpp_data;
- u64 new_entitled;
- u8 new_weight;
- ssize_t rc;
-
- if (entitlement) {
- /* Check with vio to ensure the new memory entitlement
- * can be handled.
- */
- rc = vio_cmo_entitlement_update(*entitlement);
- if (rc)
- return rc;
- }
-
- rc = h_get_mpp(&mpp_data);
- if (rc)
- return rc;
-
- if (entitlement) {
- new_weight = mpp_data.mem_weight;
- new_entitled = *entitlement;
- } else if (weight) {
- new_weight = *weight;
- new_entitled = mpp_data.entitled_mem;
- } else
- return -EINVAL;
-
- pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
- __func__, mpp_data.entitled_mem, mpp_data.mem_weight);
-
- pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
- __func__, new_entitled, new_weight);
-
- rc = plpar_hcall_norets(H_SET_MPP, new_entitled, new_weight);
- return rc;
-}
-
-/*
- * Interface for changing system parameters (variable capacity weight
- * and entitled capacity). Format of input is "param_name=value";
- * anything after value is ignored. Valid parameters at this time are
- * "partition_entitled_capacity" and "capacity_weight". We use
- * H_SET_PPP to alter parameters.
- *
- * This function should be invoked only on systems with
- * FW_FEATURE_SPLPAR.
- */
-static ssize_t lparcfg_write(struct file *file, const char __user * buf,
- size_t count, loff_t * off)
-{
- int kbuf_sz = 64;
- char kbuf[kbuf_sz];
- char *tmp;
- u64 new_entitled, *new_entitled_ptr = &new_entitled;
- u8 new_weight, *new_weight_ptr = &new_weight;
- ssize_t retval;
-
- if (!firmware_has_feature(FW_FEATURE_SPLPAR))
- return -EINVAL;
-
- if (count > kbuf_sz)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buf, count))
- return -EFAULT;
-
- kbuf[count - 1] = '\0';
- tmp = strchr(kbuf, '=');
- if (!tmp)
- return -EINVAL;
-
- *tmp++ = '\0';
-
- if (!strcmp(kbuf, "partition_entitled_capacity")) {
- char *endp;
- *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
- if (endp == tmp)
- return -EINVAL;
-
- retval = update_ppp(new_entitled_ptr, NULL);
- } else if (!strcmp(kbuf, "capacity_weight")) {
- char *endp;
- *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
- if (endp == tmp)
- return -EINVAL;
-
- retval = update_ppp(NULL, new_weight_ptr);
- } else if (!strcmp(kbuf, "entitled_memory")) {
- char *endp;
- *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
- if (endp == tmp)
- return -EINVAL;
-
- retval = update_mpp(new_entitled_ptr, NULL);
- } else if (!strcmp(kbuf, "entitled_memory_weight")) {
- char *endp;
- *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
- if (endp == tmp)
- return -EINVAL;
-
- retval = update_mpp(NULL, new_weight_ptr);
- } else
- return -EINVAL;
-
- if (retval == H_SUCCESS || retval == H_CONSTRAINED) {
- retval = count;
- } else if (retval == H_BUSY) {
- retval = -EBUSY;
- } else if (retval == H_HARDWARE) {
- retval = -EIO;
- } else if (retval == H_PARAMETER) {
- retval = -EINVAL;
- }
-
- return retval;
-}
-
-static int lparcfg_data(struct seq_file *m, void *v)
-{
- struct device_node *rootdn;
- const char *model = "";
- const char *system_id = "";
- const char *tmp;
- const unsigned int *lp_index_ptr;
- unsigned int lp_index = 0;
-
- seq_printf(m, "%s %s\n", MODULE_NAME, MODULE_VERS);
-
- rootdn = of_find_node_by_path("/");
- if (rootdn) {
- tmp = of_get_property(rootdn, "model", NULL);
- if (tmp)
- model = tmp;
- tmp = of_get_property(rootdn, "system-id", NULL);
- if (tmp)
- system_id = tmp;
- lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
- NULL);
- if (lp_index_ptr)
- lp_index = *lp_index_ptr;
- of_node_put(rootdn);
- }
- seq_printf(m, "serial_number=%s\n", system_id);
- seq_printf(m, "system_type=%s\n", model);
- seq_printf(m, "partition_id=%d\n", (int)lp_index);
-
- return pseries_lparcfg_data(m, v);
-}
-
-static int lparcfg_open(struct inode *inode, struct file *file)
-{
- return single_open(file, lparcfg_data, NULL);
-}
-
-static const struct file_operations lparcfg_fops = {
- .read = seq_read,
- .write = lparcfg_write,
- .open = lparcfg_open,
- .release = single_release,
- .llseek = seq_lseek,
-};
-
-static int __init lparcfg_init(void)
-{
- umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
-
- /* Allow writing if we have FW_FEATURE_SPLPAR */
- if (firmware_has_feature(FW_FEATURE_SPLPAR))
- mode |= S_IWUSR;
-
- if (!proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops)) {
- printk(KERN_ERR "Failed to create powerpc/lparcfg\n");
- return -EIO;
- }
- return 0;
-}
-machine_device_initcall(pseries, lparcfg_init);
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 8ae0103..6c61ec5 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -22,6 +22,7 @@ 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
+obj-$(CONFIG_LPARCFG) += lparcfg.o
ifeq ($(CONFIG_PPC_PSERIES),y)
obj-$(CONFIG_SUSPEND) += suspend.o
diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c
new file mode 100644
index 0000000..e738007
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/lparcfg.c
@@ -0,0 +1,710 @@
+/*
+ * PowerPC64 LPAR Configuration Information Driver
+ *
+ * Dave Engebretsen engebret@us.ibm.com
+ * Copyright (c) 2003 Dave Engebretsen
+ * Will Schmidt willschm@us.ibm.com
+ * SPLPAR updates, Copyright (c) 2003 Will Schmidt IBM Corporation.
+ * seq_file updates, Copyright (c) 2004 Will Schmidt IBM Corporation.
+ * Nathan Lynch nathanl@austin.ibm.com
+ * Added lparcfg_write, Copyright (C) 2004 Nathan Lynch IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This driver creates a proc file at /proc/ppc64/lparcfg which contains
+ * keyword - value pairs that specify the configuration of the partition.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/lppaca.h>
+#include <asm/hvcall.h>
+#include <asm/firmware.h>
+#include <asm/rtas.h>
+#include <asm/time.h>
+#include <asm/prom.h>
+#include <asm/vdso_datapage.h>
+#include <asm/vio.h>
+#include <asm/mmu.h>
+#include <asm/machdep.h>
+
+
+/*
+ * This isn't a module but we expose that to userspace
+ * via /proc so leave the definitions here
+ */
+#define MODULE_VERS "1.9"
+#define MODULE_NAME "lparcfg"
+
+/* #define LPARCFG_DEBUG */
+
+/*
+ * Track sum of all purrs across all processors. This is used to further
+ * calculate usage values by different applications
+ */
+static unsigned long get_purr(void)
+{
+ unsigned long sum_purr = 0;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct cpu_usage *cu;
+
+ cu = &per_cpu(cpu_usage_array, cpu);
+ sum_purr += cu->current_tb;
+ }
+ return sum_purr;
+}
+
+/*
+ * Methods used to fetch LPAR data when running on a pSeries platform.
+ */
+
+struct hvcall_ppp_data {
+ u64 entitlement;
+ u64 unallocated_entitlement;
+ u16 group_num;
+ u16 pool_num;
+ u8 capped;
+ u8 weight;
+ u8 unallocated_weight;
+ u16 active_procs_in_pool;
+ u16 active_system_procs;
+ u16 phys_platform_procs;
+ u32 max_proc_cap_avail;
+ u32 entitled_proc_cap_avail;
+};
+
+/*
+ * H_GET_PPP hcall returns info in 4 parms.
+ * entitled_capacity,unallocated_capacity,
+ * aggregation, resource_capability).
+ *
+ * R4 = Entitled Processor Capacity Percentage.
+ * R5 = Unallocated Processor Capacity Percentage.
+ * R6 (AABBCCDDEEFFGGHH).
+ * XXXX - reserved (0)
+ * XXXX - reserved (0)
+ * XXXX - Group Number
+ * XXXX - Pool Number.
+ * R7 (IIJJKKLLMMNNOOPP).
+ * XX - reserved. (0)
+ * XX - bit 0-6 reserved (0). bit 7 is Capped indicator.
+ * XX - variable processor Capacity Weight
+ * XX - Unallocated Variable Processor Capacity Weight.
+ * XXXX - Active processors in Physical Processor Pool.
+ * XXXX - Processors active on platform.
+ * R8 (QQQQRRRRRRSSSSSS). if ibm,partition-performance-parameters-level >= 1
+ * XXXX - Physical platform procs allocated to virtualization.
+ * XXXXXX - Max procs capacity % available to the partitions pool.
+ * XXXXXX - Entitled procs capacity % available to the
+ * partitions pool.
+ */
+static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data)
+{
+ unsigned long rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9(H_GET_PPP, retbuf);
+
+ ppp_data->entitlement = retbuf[0];
+ ppp_data->unallocated_entitlement = retbuf[1];
+
+ ppp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
+ ppp_data->pool_num = retbuf[2] & 0xffff;
+
+ ppp_data->capped = (retbuf[3] >> 6 * 8) & 0x01;
+ ppp_data->weight = (retbuf[3] >> 5 * 8) & 0xff;
+ ppp_data->unallocated_weight = (retbuf[3] >> 4 * 8) & 0xff;
+ ppp_data->active_procs_in_pool = (retbuf[3] >> 2 * 8) & 0xffff;
+ ppp_data->active_system_procs = retbuf[3] & 0xffff;
+
+ ppp_data->phys_platform_procs = retbuf[4] >> 6 * 8;
+ ppp_data->max_proc_cap_avail = (retbuf[4] >> 3 * 8) & 0xffffff;
+ ppp_data->entitled_proc_cap_avail = retbuf[4] & 0xffffff;
+
+ return rc;
+}
+
+static unsigned h_pic(unsigned long *pool_idle_time,
+ unsigned long *num_procs)
+{
+ unsigned long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_PIC, retbuf);
+
+ *pool_idle_time = retbuf[0];
+ *num_procs = retbuf[1];
+
+ return rc;
+}
+
+/*
+ * parse_ppp_data
+ * Parse out the data returned from h_get_ppp and h_pic
+ */
+static void parse_ppp_data(struct seq_file *m)
+{
+ struct hvcall_ppp_data ppp_data;
+ struct device_node *root;
+ const int *perf_level;
+ int rc;
+
+ rc = h_get_ppp(&ppp_data);
+ if (rc)
+ return;
+
+ seq_printf(m, "partition_entitled_capacity=%lld\n",
+ ppp_data.entitlement);
+ seq_printf(m, "group=%d\n", ppp_data.group_num);
+ seq_printf(m, "system_active_processors=%d\n",
+ ppp_data.active_system_procs);
+
+ /* pool related entries are appropriate for shared configs */
+ if (lppaca_shared_proc(get_lppaca())) {
+ unsigned long pool_idle_time, pool_procs;
+
+ seq_printf(m, "pool=%d\n", ppp_data.pool_num);
+
+ /* report pool_capacity in percentage */
+ seq_printf(m, "pool_capacity=%d\n",
+ ppp_data.active_procs_in_pool * 100);
+
+ h_pic(&pool_idle_time, &pool_procs);
+ seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time);
+ seq_printf(m, "pool_num_procs=%ld\n", pool_procs);
+ }
+
+ seq_printf(m, "unallocated_capacity_weight=%d\n",
+ ppp_data.unallocated_weight);
+ seq_printf(m, "capacity_weight=%d\n", ppp_data.weight);
+ seq_printf(m, "capped=%d\n", ppp_data.capped);
+ seq_printf(m, "unallocated_capacity=%lld\n",
+ ppp_data.unallocated_entitlement);
+
+ /* The last bits of information returned from h_get_ppp are only
+ * valid if the ibm,partition-performance-parameters-level
+ * property is >= 1.
+ */
+ root = of_find_node_by_path("/");
+ if (root) {
+ perf_level = of_get_property(root,
+ "ibm,partition-performance-parameters-level",
+ NULL);
+ if (perf_level && (*perf_level >= 1)) {
+ seq_printf(m,
+ "physical_procs_allocated_to_virtualization=%d\n",
+ ppp_data.phys_platform_procs);
+ seq_printf(m, "max_proc_capacity_available=%d\n",
+ ppp_data.max_proc_cap_avail);
+ seq_printf(m, "entitled_proc_capacity_available=%d\n",
+ ppp_data.entitled_proc_cap_avail);
+ }
+
+ of_node_put(root);
+ }
+}
+
+/**
+ * parse_mpp_data
+ * Parse out data returned from h_get_mpp
+ */
+static void parse_mpp_data(struct seq_file *m)
+{
+ struct hvcall_mpp_data mpp_data;
+ int rc;
+
+ rc = h_get_mpp(&mpp_data);
+ if (rc)
+ return;
+
+ seq_printf(m, "entitled_memory=%ld\n", mpp_data.entitled_mem);
+
+ if (mpp_data.mapped_mem != -1)
+ seq_printf(m, "mapped_entitled_memory=%ld\n",
+ mpp_data.mapped_mem);
+
+ seq_printf(m, "entitled_memory_group_number=%d\n", mpp_data.group_num);
+ seq_printf(m, "entitled_memory_pool_number=%d\n", mpp_data.pool_num);
+
+ seq_printf(m, "entitled_memory_weight=%d\n", mpp_data.mem_weight);
+ seq_printf(m, "unallocated_entitled_memory_weight=%d\n",
+ mpp_data.unallocated_mem_weight);
+ seq_printf(m, "unallocated_io_mapping_entitlement=%ld\n",
+ mpp_data.unallocated_entitlement);
+
+ if (mpp_data.pool_size != -1)
+ seq_printf(m, "entitled_memory_pool_size=%ld bytes\n",
+ mpp_data.pool_size);
+
+ seq_printf(m, "entitled_memory_loan_request=%ld\n",
+ mpp_data.loan_request);
+
+ seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
+}
+
+/**
+ * parse_mpp_x_data
+ * Parse out data returned from h_get_mpp_x
+ */
+static void parse_mpp_x_data(struct seq_file *m)
+{
+ struct hvcall_mpp_x_data mpp_x_data;
+
+ if (!firmware_has_feature(FW_FEATURE_XCMO))
+ return;
+ if (h_get_mpp_x(&mpp_x_data))
+ return;
+
+ seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
+
+ if (mpp_x_data.pool_coalesced_bytes)
+ seq_printf(m, "pool_coalesced_bytes=%ld\n",
+ mpp_x_data.pool_coalesced_bytes);
+ if (mpp_x_data.pool_purr_cycles)
+ seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
+ if (mpp_x_data.pool_spurr_cycles)
+ seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
+}
+
+#define SPLPAR_CHARACTERISTICS_TOKEN 20
+#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
+
+/*
+ * parse_system_parameter_string()
+ * Retrieve the potential_processors, max_entitled_capacity and friends
+ * through the get-system-parameter rtas call. Replace keyword strings as
+ * necessary.
+ */
+static void parse_system_parameter_string(struct seq_file *m)
+{
+ int call_status;
+
+ unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
+ if (!local_buffer) {
+ printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
+ __FILE__, __func__, __LINE__);
+ return;
+ }
+
+ spin_lock(&rtas_data_buf_lock);
+ memset(rtas_data_buf, 0, SPLPAR_MAXLENGTH);
+ call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
+ NULL,
+ SPLPAR_CHARACTERISTICS_TOKEN,
+ __pa(rtas_data_buf),
+ RTAS_DATA_BUF_SIZE);
+ memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH);
+ local_buffer[SPLPAR_MAXLENGTH - 1] = '\0';
+ spin_unlock(&rtas_data_buf_lock);
+
+ if (call_status != 0) {
+ printk(KERN_INFO
+ "%s %s Error calling get-system-parameter (0x%x)\n",
+ __FILE__, __func__, call_status);
+ } else {
+ int splpar_strlen;
+ int idx, w_idx;
+ char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
+ if (!workbuffer) {
+ printk(KERN_ERR "%s %s kmalloc failure at line %d\n",
+ __FILE__, __func__, __LINE__);
+ kfree(local_buffer);
+ return;
+ }
+#ifdef LPARCFG_DEBUG
+ printk(KERN_INFO "success calling get-system-parameter\n");
+#endif
+ splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
+ local_buffer += 2; /* step over strlen value */
+
+ w_idx = 0;
+ idx = 0;
+ while ((*local_buffer) && (idx < splpar_strlen)) {
+ workbuffer[w_idx++] = local_buffer[idx++];
+ if ((local_buffer[idx] == ',')
+ || (local_buffer[idx] == '\0')) {
+ workbuffer[w_idx] = '\0';
+ if (w_idx) {
+ /* avoid the empty string */
+ seq_printf(m, "%s\n", workbuffer);
+ }
+ memset(workbuffer, 0, SPLPAR_MAXLENGTH);
+ idx++; /* skip the comma */
+ w_idx = 0;
+ } else if (local_buffer[idx] == '=') {
+ /* code here to replace workbuffer contents
+ with different keyword strings */
+ if (0 == strcmp(workbuffer, "MaxEntCap")) {
+ strcpy(workbuffer,
+ "partition_max_entitled_capacity");
+ w_idx = strlen(workbuffer);
+ }
+ if (0 == strcmp(workbuffer, "MaxPlatProcs")) {
+ strcpy(workbuffer,
+ "system_potential_processors");
+ w_idx = strlen(workbuffer);
+ }
+ }
+ }
+ kfree(workbuffer);
+ local_buffer -= 2; /* back up over strlen value */
+ }
+ kfree(local_buffer);
+}
+
+/* Return the number of processors in the system.
+ * This function reads through the device tree and counts
+ * the virtual processors, this does not include threads.
+ */
+static int lparcfg_count_active_processors(void)
+{
+ struct device_node *cpus_dn = NULL;
+ int count = 0;
+
+ while ((cpus_dn = of_find_node_by_type(cpus_dn, "cpu"))) {
+#ifdef LPARCFG_DEBUG
+ printk(KERN_ERR "cpus_dn %p\n", cpus_dn);
+#endif
+ count++;
+ }
+ return count;
+}
+
+static void pseries_cmo_data(struct seq_file *m)
+{
+ int cpu;
+ unsigned long cmo_faults = 0;
+ unsigned long cmo_fault_time = 0;
+
+ seq_printf(m, "cmo_enabled=%d\n", firmware_has_feature(FW_FEATURE_CMO));
+
+ if (!firmware_has_feature(FW_FEATURE_CMO))
+ return;
+
+ for_each_possible_cpu(cpu) {
+ cmo_faults += be64_to_cpu(lppaca_of(cpu).cmo_faults);
+ cmo_fault_time += be64_to_cpu(lppaca_of(cpu).cmo_fault_time);
+ }
+
+ seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
+ seq_printf(m, "cmo_fault_time_usec=%lu\n",
+ cmo_fault_time / tb_ticks_per_usec);
+ seq_printf(m, "cmo_primary_psp=%d\n", cmo_get_primary_psp());
+ seq_printf(m, "cmo_secondary_psp=%d\n", cmo_get_secondary_psp());
+ seq_printf(m, "cmo_page_size=%lu\n", cmo_get_page_size());
+}
+
+static void splpar_dispatch_data(struct seq_file *m)
+{
+ int cpu;
+ unsigned long dispatches = 0;
+ unsigned long dispatch_dispersions = 0;
+
+ for_each_possible_cpu(cpu) {
+ dispatches += be32_to_cpu(lppaca_of(cpu).yield_count);
+ dispatch_dispersions +=
+ be32_to_cpu(lppaca_of(cpu).dispersion_count);
+ }
+
+ seq_printf(m, "dispatches=%lu\n", dispatches);
+ seq_printf(m, "dispatch_dispersions=%lu\n", dispatch_dispersions);
+}
+
+static void parse_em_data(struct seq_file *m)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ if (firmware_has_feature(FW_FEATURE_LPAR) &&
+ plpar_hcall(H_GET_EM_PARMS, retbuf) == H_SUCCESS)
+ seq_printf(m, "power_mode_data=%016lx\n", retbuf[0]);
+}
+
+static int pseries_lparcfg_data(struct seq_file *m, void *v)
+{
+ int partition_potential_processors;
+ int partition_active_processors;
+ struct device_node *rtas_node;
+ const int *lrdrp = NULL;
+
+ rtas_node = of_find_node_by_path("/rtas");
+ if (rtas_node)
+ lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+
+ if (lrdrp == NULL) {
+ partition_potential_processors = vdso_data->processorCount;
+ } else {
+ partition_potential_processors = *(lrdrp + 4);
+ }
+ of_node_put(rtas_node);
+
+ partition_active_processors = lparcfg_count_active_processors();
+
+ if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+ /* this call handles the ibm,get-system-parameter contents */
+ parse_system_parameter_string(m);
+ parse_ppp_data(m);
+ parse_mpp_data(m);
+ parse_mpp_x_data(m);
+ pseries_cmo_data(m);
+ splpar_dispatch_data(m);
+
+ seq_printf(m, "purr=%ld\n", get_purr());
+ } else { /* non SPLPAR case */
+
+ seq_printf(m, "system_active_processors=%d\n",
+ partition_potential_processors);
+
+ seq_printf(m, "system_potential_processors=%d\n",
+ partition_potential_processors);
+
+ seq_printf(m, "partition_max_entitled_capacity=%d\n",
+ partition_potential_processors * 100);
+
+ seq_printf(m, "partition_entitled_capacity=%d\n",
+ partition_active_processors * 100);
+ }
+
+ seq_printf(m, "partition_active_processors=%d\n",
+ partition_active_processors);
+
+ seq_printf(m, "partition_potential_processors=%d\n",
+ partition_potential_processors);
+
+ seq_printf(m, "shared_processor_mode=%d\n",
+ lppaca_shared_proc(get_lppaca()));
+
+ seq_printf(m, "slb_size=%d\n", mmu_slb_size);
+
+ parse_em_data(m);
+
+ return 0;
+}
+
+static ssize_t update_ppp(u64 *entitlement, u8 *weight)
+{
+ struct hvcall_ppp_data ppp_data;
+ u8 new_weight;
+ u64 new_entitled;
+ ssize_t retval;
+
+ /* Get our current parameters */
+ retval = h_get_ppp(&ppp_data);
+ if (retval)
+ return retval;
+
+ if (entitlement) {
+ new_weight = ppp_data.weight;
+ new_entitled = *entitlement;
+ } else if (weight) {
+ new_weight = *weight;
+ new_entitled = ppp_data.entitlement;
+ } else
+ return -EINVAL;
+
+ pr_debug("%s: current_entitled = %llu, current_weight = %u\n",
+ __func__, ppp_data.entitlement, ppp_data.weight);
+
+ pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
+ __func__, new_entitled, new_weight);
+
+ retval = plpar_hcall_norets(H_SET_PPP, new_entitled, new_weight);
+ return retval;
+}
+
+/**
+ * update_mpp
+ *
+ * Update the memory entitlement and weight for the partition. Caller must
+ * specify either a new entitlement or weight, not both, to be updated
+ * since the h_set_mpp call takes both entitlement and weight as parameters.
+ */
+static ssize_t update_mpp(u64 *entitlement, u8 *weight)
+{
+ struct hvcall_mpp_data mpp_data;
+ u64 new_entitled;
+ u8 new_weight;
+ ssize_t rc;
+
+ if (entitlement) {
+ /* Check with vio to ensure the new memory entitlement
+ * can be handled.
+ */
+ rc = vio_cmo_entitlement_update(*entitlement);
+ if (rc)
+ return rc;
+ }
+
+ rc = h_get_mpp(&mpp_data);
+ if (rc)
+ return rc;
+
+ if (entitlement) {
+ new_weight = mpp_data.mem_weight;
+ new_entitled = *entitlement;
+ } else if (weight) {
+ new_weight = *weight;
+ new_entitled = mpp_data.entitled_mem;
+ } else
+ return -EINVAL;
+
+ pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
+ __func__, mpp_data.entitled_mem, mpp_data.mem_weight);
+
+ pr_debug("%s: new_entitled = %llu, new_weight = %u\n",
+ __func__, new_entitled, new_weight);
+
+ rc = plpar_hcall_norets(H_SET_MPP, new_entitled, new_weight);
+ return rc;
+}
+
+/*
+ * Interface for changing system parameters (variable capacity weight
+ * and entitled capacity). Format of input is "param_name=value";
+ * anything after value is ignored. Valid parameters at this time are
+ * "partition_entitled_capacity" and "capacity_weight". We use
+ * H_SET_PPP to alter parameters.
+ *
+ * This function should be invoked only on systems with
+ * FW_FEATURE_SPLPAR.
+ */
+static ssize_t lparcfg_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * off)
+{
+ int kbuf_sz = 64;
+ char kbuf[kbuf_sz];
+ char *tmp;
+ u64 new_entitled, *new_entitled_ptr = &new_entitled;
+ u8 new_weight, *new_weight_ptr = &new_weight;
+ ssize_t retval;
+
+ if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+ return -EINVAL;
+
+ if (count > kbuf_sz)
+ return -EINVAL;
+
+ if (copy_from_user(kbuf, buf, count))
+ return -EFAULT;
+
+ kbuf[count - 1] = '\0';
+ tmp = strchr(kbuf, '=');
+ if (!tmp)
+ return -EINVAL;
+
+ *tmp++ = '\0';
+
+ if (!strcmp(kbuf, "partition_entitled_capacity")) {
+ char *endp;
+ *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
+ if (endp == tmp)
+ return -EINVAL;
+
+ retval = update_ppp(new_entitled_ptr, NULL);
+ } else if (!strcmp(kbuf, "capacity_weight")) {
+ char *endp;
+ *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
+ if (endp == tmp)
+ return -EINVAL;
+
+ retval = update_ppp(NULL, new_weight_ptr);
+ } else if (!strcmp(kbuf, "entitled_memory")) {
+ char *endp;
+ *new_entitled_ptr = (u64) simple_strtoul(tmp, &endp, 10);
+ if (endp == tmp)
+ return -EINVAL;
+
+ retval = update_mpp(new_entitled_ptr, NULL);
+ } else if (!strcmp(kbuf, "entitled_memory_weight")) {
+ char *endp;
+ *new_weight_ptr = (u8) simple_strtoul(tmp, &endp, 10);
+ if (endp == tmp)
+ return -EINVAL;
+
+ retval = update_mpp(NULL, new_weight_ptr);
+ } else
+ return -EINVAL;
+
+ if (retval == H_SUCCESS || retval == H_CONSTRAINED) {
+ retval = count;
+ } else if (retval == H_BUSY) {
+ retval = -EBUSY;
+ } else if (retval == H_HARDWARE) {
+ retval = -EIO;
+ } else if (retval == H_PARAMETER) {
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+static int lparcfg_data(struct seq_file *m, void *v)
+{
+ struct device_node *rootdn;
+ const char *model = "";
+ const char *system_id = "";
+ const char *tmp;
+ const unsigned int *lp_index_ptr;
+ unsigned int lp_index = 0;
+
+ seq_printf(m, "%s %s\n", MODULE_NAME, MODULE_VERS);
+
+ rootdn = of_find_node_by_path("/");
+ if (rootdn) {
+ tmp = of_get_property(rootdn, "model", NULL);
+ if (tmp)
+ model = tmp;
+ tmp = of_get_property(rootdn, "system-id", NULL);
+ if (tmp)
+ system_id = tmp;
+ lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
+ NULL);
+ if (lp_index_ptr)
+ lp_index = *lp_index_ptr;
+ of_node_put(rootdn);
+ }
+ seq_printf(m, "serial_number=%s\n", system_id);
+ seq_printf(m, "system_type=%s\n", model);
+ seq_printf(m, "partition_id=%d\n", (int)lp_index);
+
+ return pseries_lparcfg_data(m, v);
+}
+
+static int lparcfg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, lparcfg_data, NULL);
+}
+
+static const struct file_operations lparcfg_fops = {
+ .read = seq_read,
+ .write = lparcfg_write,
+ .open = lparcfg_open,
+ .release = single_release,
+ .llseek = seq_lseek,
+};
+
+static int __init lparcfg_init(void)
+{
+ umode_t mode = S_IRUSR | S_IRGRP | S_IROTH;
+
+ /* Allow writing if we have FW_FEATURE_SPLPAR */
+ if (firmware_has_feature(FW_FEATURE_SPLPAR))
+ mode |= S_IWUSR;
+
+ if (!proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops)) {
+ printk(KERN_ERR "Failed to create powerpc/lparcfg\n");
+ return -EIO;
+ }
+ return 0;
+}
+machine_device_initcall(pseries, lparcfg_init);
^ permalink raw reply related
* [PATCH v12] ASoC: fsl: Add S/PDIF machine driver
From: Nicolin Chen @ 2013-08-28 4:04 UTC (permalink / raw)
To: broonie, s.hauer, swarren
Cc: mark.rutland, devicetree, alsa-devel, lars, tomasz.figa,
rob.herring, p.zabel, shawn.guo, linuxppc-dev
This patch implements a device-tree-only machine driver for Freescale
i.MX series Soc. It works with spdif_transmitter/spdif_receiver and
fsl_spdif.c drivers.
Signed-off-by: Nicolin Chen <b42378@freescale.com>
---
Changelog
v11->v12:
* Dropped unused spdif_pdev.
* Register spdif-dit/dir depending on DT bool property.
v10->v11:
* Use boolean properties for spdif-out/in switch instead of codec phandles.
* Accordingly create dummy codec driver in probe() instead of DT nodes.
.../devicetree/bindings/sound/imx-audio-spdif.txt | 34 +++++
sound/soc/fsl/Kconfig | 11 ++
sound/soc/fsl/Makefile | 2 +
sound/soc/fsl/imx-spdif.c | 148 ++++++++++++++++++++
4 files changed, 195 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
create mode 100644 sound/soc/fsl/imx-spdif.c
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
new file mode 100644
index 0000000..7d13479
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
@@ -0,0 +1,34 @@
+Freescale i.MX audio complex with S/PDIF transceiver
+
+Required properties:
+
+ - compatible : "fsl,imx-audio-spdif"
+
+ - model : The user-visible name of this sound complex
+
+ - spdif-controller : The phandle of the i.MX S/PDIF controller
+
+
+Optional properties:
+
+ - spdif-out : This is a boolean property. If present, the transmitting
+ function of S/PDIF will be enabled, indicating there's a physical
+ S/PDIF out connector/jack on the board or it's connecting to some
+ other IP block, such as an HDMI encoder/display-controller.
+
+ - spdif-in : This is a boolean property. If present, the receiving
+ function of S/PDIF will be enabled, indicating there's a physical
+ S/PDIF in connector/jack on the board.
+
+* Note: At least one of these two properties should be set in the DT binding.
+
+
+Example:
+
+sound-spdif {
+ compatible = "fsl,imx-audio-spdif";
+ model = "imx-spdif";
+ spdif-controller = <&spdif>;
+ spdif-out;
+ spdif-in;
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index cd088cc..a708380 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -193,6 +193,17 @@ config SND_SOC_IMX_SGTL5000
Say Y if you want to add support for SoC audio on an i.MX board with
a sgtl5000 codec.
+config SND_SOC_IMX_SPDIF
+ tristate "SoC Audio support for i.MX boards with S/PDIF"
+ select SND_SOC_IMX_PCM_DMA
+ select SND_SOC_FSL_SPDIF
+ select SND_SOC_FSL_UTILS
+ select SND_SOC_SPDIF
+ help
+ SoC Audio support for i.MX boards with S/PDIF
+ Say Y if you want to add support for SoC audio on an i.MX board with
+ a S/DPDIF.
+
config SND_SOC_IMX_MC13783
tristate "SoC Audio support for I.MX boards with mc13783"
depends on MFD_MC13783 && ARM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 4b5970e..e2aaff7 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -45,6 +45,7 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-wm8962-objs := imx-wm8962.o
+snd-soc-imx-spdif-objs :=imx-spdif.o
snd-soc-imx-mc13783-objs := imx-mc13783.o
obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
@@ -53,4 +54,5 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
+obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
new file mode 100644
index 0000000..816013b
--- /dev/null
+++ b/sound/soc/fsl/imx-spdif.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+
+struct imx_spdif_data {
+ struct snd_soc_dai_link dai[2];
+ struct snd_soc_card card;
+ struct platform_device *txdev;
+ struct platform_device *rxdev;
+};
+
+static int imx_spdif_audio_probe(struct platform_device *pdev)
+{
+ struct device_node *spdif_np, *np = pdev->dev.of_node;
+ struct imx_spdif_data *data;
+ int ret = 0, num_links = 0;
+
+ spdif_np = of_parse_phandle(np, "spdif-controller", 0);
+ if (!spdif_np) {
+ dev_err(&pdev->dev, "failed to find spdif-controller\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev, "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ if (of_property_read_bool(np, "spdif-out")) {
+ data->dai[num_links].name = "S/PDIF TX";
+ data->dai[num_links].stream_name = "S/PDIF PCM Playback";
+ data->dai[num_links].codec_dai_name = "dit-hifi";
+ data->dai[num_links].codec_name = "spdif-dit";
+ data->dai[num_links].cpu_of_node = spdif_np;
+ data->dai[num_links].platform_of_node = spdif_np;
+ num_links++;
+
+ data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0);
+ if (IS_ERR(data->txdev)) {
+ ret = PTR_ERR(data->txdev);
+ dev_err(&pdev->dev, "register dit failed: %d\n", ret);
+ goto end;
+ }
+ }
+
+ if (of_property_read_bool(np, "spdif-in")) {
+ data->dai[num_links].name = "S/PDIF RX";
+ data->dai[num_links].stream_name = "S/PDIF PCM Capture";
+ data->dai[num_links].codec_dai_name = "dir-hifi";
+ data->dai[num_links].codec_name = "spdif-dir";
+ data->dai[num_links].cpu_of_node = spdif_np;
+ data->dai[num_links].platform_of_node = spdif_np;
+ num_links++;
+
+ data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0);
+ if (IS_ERR(data->rxdev)) {
+ ret = PTR_ERR(data->rxdev);
+ dev_err(&pdev->dev, "register dir failed: %d\n", ret);
+ goto error_dit;
+ }
+ }
+
+ if (!num_links) {
+ dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
+ goto error_dir;
+ }
+
+ data->card.dev = &pdev->dev;
+ data->card.num_links = num_links;
+ data->card.dai_link = data->dai;
+
+ ret = snd_soc_of_parse_card_name(&data->card, "model");
+ if (ret)
+ goto error_dir;
+
+ ret = snd_soc_register_card(&data->card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret);
+ goto error_dir;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ goto end;
+
+error_dir:
+ if (data->rxdev)
+ platform_device_unregister(data->rxdev);
+error_dit:
+ if (data->txdev)
+ platform_device_unregister(data->txdev);
+end:
+ if (spdif_np)
+ of_node_put(spdif_np);
+
+ return ret;
+}
+
+static int imx_spdif_audio_remove(struct platform_device *pdev)
+{
+ struct imx_spdif_data *data = platform_get_drvdata(pdev);
+
+ if (data->rxdev)
+ platform_device_unregister(data->rxdev);
+ if (data->txdev)
+ platform_device_unregister(data->txdev);
+
+ snd_soc_unregister_card(&data->card);
+
+ return 0;
+}
+
+static const struct of_device_id imx_spdif_dt_ids[] = {
+ { .compatible = "fsl,imx-audio-spdif", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
+
+static struct platform_driver imx_spdif_driver = {
+ .driver = {
+ .name = "imx-spdif",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_spdif_dt_ids,
+ },
+ .probe = imx_spdif_audio_probe,
+ .remove = imx_spdif_audio_remove,
+};
+
+module_platform_driver(imx_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-spdif");
--
1.7.1
^ permalink raw reply related
* RE: [PATCH v2 2/3] powerpc/85xx: add hardware automatically enter altivec idle state
From: Wang Dongsheng-B40534 @ 2013-08-28 6:08 UTC (permalink / raw)
To: Wang Dongsheng-B40534, Wood Scott-B07421,
galak@kernel.crashing.org
Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1377592900-5020-2-git-send-email-dongsheng.wang@freescale.com>
> -----Original Message-----
> From: Wang Dongsheng-B40534
> Sent: Tuesday, August 27, 2013 4:42 PM
> To: Wood Scott-B07421; galak@kernel.crashing.org
> Cc: linuxppc-dev@lists.ozlabs.org; Wang Dongsheng-B40534
> Subject: [PATCH v2 2/3] powerpc/85xx: add hardware automatically enter
> altivec idle state
>=20
> From: Wang Dongsheng <dongsheng.wang@freescale.com>
>=20
> Each core's AltiVec unit may be placed into a power savings mode
> by turning off power to the unit. Core hardware will automatically
> power down the AltiVec unit after no AltiVec instructions have
> executed in N cycles. The AltiVec power-control is triggered by hardware.
>=20
> Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
> ---
> *v2:
> Remove:
> delete setup_idle_hw_governor function.
> delete "Fix erratum" for rev1.
>=20
> Move:
> move setup_* into __setup/restore_cpu_e6500.
>=20
> diff --git a/arch/powerpc/include/asm/reg_booke.h
> b/arch/powerpc/include/asm/reg_booke.h
> index 86ede76..8364bbe 100644
> --- a/arch/powerpc/include/asm/reg_booke.h
> +++ b/arch/powerpc/include/asm/reg_booke.h
> @@ -217,6 +217,9 @@
> #define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity
> checking */
> #define CCR1_TCS 0x00000080 /* Timer Clock Select */
>=20
> +/* Bit definitions for PWRMGTCR0. */
> +#define PWRMGTCR0_ALTIVEC_IDLE (1 << 22) /* Altivec idle enable */
> +
> /* Bit definitions for the MCSR. */
> #define MCSR_MCS 0x80000000 /* Machine Check Summary */
> #define MCSR_IB 0x40000000 /* Instruction PLB Error */
> diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> index bfb18c7..90bbb46 100644
> --- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
> @@ -58,6 +58,7 @@ _GLOBAL(__setup_cpu_e6500)
> #ifdef CONFIG_PPC64
> bl .setup_altivec_ivors
> #endif
> + bl setup_altivec_idle
> bl __setup_cpu_e5500
> mtlr r6
> blr
> @@ -119,6 +120,7 @@ _GLOBAL(__setup_cpu_e5500)
> _GLOBAL(__restore_cpu_e6500)
> mflr r5
> bl .setup_altivec_ivors
> + bl setup_altivec_idle
> bl __restore_cpu_e5500
> mtlr r5
> blr
> diff --git a/arch/powerpc/platforms/85xx/common.c
> b/arch/powerpc/platforms/85xx/common.c
> index d0861a0..93b563b 100644
> --- a/arch/powerpc/platforms/85xx/common.c
> +++ b/arch/powerpc/platforms/85xx/common.c
> @@ -11,6 +11,16 @@
>=20
> #include "mpc85xx.h"
>=20
> +#define MAX_BIT 64
> +
This should be change to 63, i will fix this in next patch.
- dongsheng
^ 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