* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Viresh Kumar @ 2014-07-23 4:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405957142-19416-15-git-send-email-ttynkkynen@nvidia.com>
On 21 July 2014 21:09, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> index 7364a53..df3c73e 100644
> --- a/drivers/cpufreq/Kconfig.arm
> +++ b/drivers/cpufreq/Kconfig.arm
> @@ -244,6 +244,7 @@ config ARM_SPEAR_CPUFREQ
> config ARM_TEGRA_CPUFREQ
> bool "TEGRA CPUFreq support"
> depends on ARCH_TEGRA
> + depends on GENERIC_CPUFREQ_CPU0
Wouldn't this also disturb the existing cpufreq driver for earlier
tegra platforms? i.e. we don't need cpufreq-cpu0 for them
atleast as of now.
> default y
> help
> This adds the CPUFreq driver support for TEGRA SOCs.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index db6d9a2..3437d24 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
> obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
> obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
> obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
> +obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra124-cpufreq.o
Maybe, you can update the same line if you want.
> obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
>
> ##################################################################################
> diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
> +static struct cpufreq_frequency_table *freq_table;
> +
> +static struct device *cpu_dev;
> +static struct clk *cpu_clk;
> +static struct clk *pllp_clk;
> +static struct clk *pllx_clk;
> +static struct clk *dfll_clk;
The routines in this file are going to be called just once at boot, right?
In that case we are actually wasting some memory by creating globals.
Probably just move all these in a struct and allocate it at runtime.
> +static int tegra124_cpu_switch_to_dfll(void)
> +{
> + struct clk *original_cpu_clk_parent;
> + unsigned long rate;
> + struct dev_pm_opp *opp;
> + int ret;
> +
> + rate = clk_get_rate(cpu_clk);
> + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
> + if (IS_ERR(opp))
> + return PTR_ERR(opp);
> +
> + ret = clk_set_rate(dfll_clk, rate);
> + if (ret)
> + return ret;
> +
> + original_cpu_clk_parent = clk_get_parent(cpu_clk);
> + clk_set_parent(cpu_clk, pllp_clk);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(dfll_clk);
> + if (ret)
> + goto out_switch_to_original_parent;
> +
> + clk_set_parent(cpu_clk, dfll_clk);
> +
> + return 0;
> +
> +out_switch_to_original_parent:
> + clk_set_parent(cpu_clk, original_cpu_clk_parent);
> +
> + return ret;
> +}
> +
> +static struct platform_device_info cpufreq_cpu0_devinfo = {
> + .name = "cpufreq-cpu0",
> +};
> +
> +static int tegra124_cpufreq_probe(struct platform_device *pdev)
> +{
> + int ret;
> +
> + cpu_dev = get_cpu_device(0);
> + if (!cpu_dev)
> + return -ENODEV;
> +
Shouldn't we do a of_node_get() here?
> + cpu_clk = of_clk_get_by_name(cpu_dev->of_node, "cpu_g");
> + if (IS_ERR(cpu_clk))
> + return PTR_ERR(cpu_clk);
> +
> + dfll_clk = of_clk_get_by_name(cpu_dev->of_node, "dfll");
> + if (IS_ERR(dfll_clk)) {
> + ret = PTR_ERR(dfll_clk);
> + goto out_put_cpu_clk;
> + }
> +
> + pllx_clk = of_clk_get_by_name(cpu_dev->of_node, "pll_x");
> + if (IS_ERR(pllx_clk)) {
> + ret = PTR_ERR(pllx_clk);
> + goto out_put_dfll_clk;
> + }
> +
> + pllp_clk = of_clk_get_by_name(cpu_dev->of_node, "pll_p");
> + if (IS_ERR(pllp_clk)) {
> + ret = PTR_ERR(pllp_clk);
> + goto out_put_pllx_clk;
> + }
> +
> + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
> + if (ret)
> + goto out_put_pllp_clk;
Why do you need this? cpufreq-cpu0 also does it and this freq_table is
just not getting used at all then.
> +
> + ret = tegra124_cpu_switch_to_dfll();
> + if (ret)
> + goto out_free_table;
> +
> + platform_device_register_full(&cpufreq_cpu0_devinfo);
> +
> + return 0;
> +
> +out_free_table:
> + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
> +out_put_pllp_clk:
> + clk_put(pllp_clk);
> +out_put_pllx_clk:
> + clk_put(pllx_clk);
> +out_put_dfll_clk:
> + clk_put(dfll_clk);
> +out_put_cpu_clk:
> + clk_put(cpu_clk);
> +
> + return ret;
> +}
> +
> +static struct platform_driver tegra124_cpufreq_platdrv = {
> + .driver = {
> + .name = "cpufreq-tegra124",
> + .owner = THIS_MODULE,
> + },
> + .probe = tegra124_cpufreq_probe,
> +};
> +
> +static const struct of_device_id soc_of_matches[] = {
> + { .compatible = "nvidia,tegra124", },
> + {}
> +};
> +
> +static int __init tegra_cpufreq_init(void)
> +{
> + int ret;
> + struct platform_device *pdev;
> +
> + if (!of_find_matching_node(NULL, soc_of_matches))
> + return -ENODEV;
> +
> + ret = platform_driver_register(&tegra124_cpufreq_platdrv);
> + if (ret)
> + return ret;
> +
> + pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
> + if (IS_ERR(pdev)) {
> + platform_driver_unregister(&tegra124_cpufreq_platdrv);
> + return PTR_ERR(pdev);
> + }
Why create another unnecessary platform-device/driver here? If
of_find_matching_node() passes and you really need to probe cpufreq-cpu0
here, then just remove the other two calls and move probe's implementation
here only.
> + return 0;
> +}
> +
> +MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
> +MODULE_DESCRIPTION("cpufreq driver for nVIDIA Tegra124");
> +MODULE_LICENSE("GPLv2");
> +module_init(tegra_cpufreq_init);
> --
> 1.8.1.5
>
^ permalink raw reply
* [PATCH 2/3] ARM: smp_scu: enable SCU standby support
From: Shawn Guo @ 2014-07-23 4:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140722161331.GN2219@arm.com>
On Tue, Jul 22, 2014 at 05:13:31PM +0100, Catalin Marinas wrote:
> And we don't know the behaviour of setting this bit on such A9 early
> revisions. So we can try to (1) find out if there are any in the field,
> (2) read the RTL to see if anything happens or (3) add a check in Linux
> for such revisions. I think (3) should be the case but you need to figure
> out which revisions these are.
Can I ask the favor from you ARM folks on that, since I cannot figure
it out from any public information?
Shawn
^ permalink raw reply
* [RFC] cpufreq: Add bindings for CPU clock sharing topology
From: Viresh Kumar @ 2014-07-23 4:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABGGisyDf7xt7CNii_NJ_stvBGNEeiXBMFxNkA2myS8OQ-VCtw@mail.gmail.com>
On 21 July 2014 22:30, Rob Herring <rob.herring@linaro.org> wrote:
> To me, but every time I suggest adding things to the topology the ARM
> folks object... I really think we should have built the topology into
> the /cpus hierarchy. Then we could add properties at the correct place
> in the hierarchy where they are common.
>
> I don't really like the proposal here. It just doesn't look like a
> clean description of the h/w.
I knew it wouldn't be easy to get these bindings correctly in the first
attempt atleast, but I still went for it so that this thread can progress:
https://lkml.org/lkml/2014/7/18/3
There are changes waiting to get some kind of intermediate solution
in, so that other platforms can reuse cpufreq-cpu0 driver. Also, so that
cpufreq-cpu0 can be converted to cpufreq-generic, so that it can support
almost any platform.
Can you please reply to that thread to suggest some intermediate
solution that we can get fixed in 3.17? Mvebu and Krait are waiting for
these patches to get in..
The solution can be simple enough as right now we have only two kinds
of platforms:
- All CPUs share clock
- All CPUs have separate clocks
The most simple solution of that could have been a Kconfig entry, but that
would be a problem for multi-arch builds if these platforms do want to get
build with multi-arch config. Otherwise we have to get some binding in
place for 3.17..
Please see if you can get that thread going :)
> Ignoring compatibility, I would like to see something like
> operating-points and/or the clock properties be moved up to /cpus if
> they are shared and be per cpu node when they are not. This of course
> does not work if you have independent OPPs for each cluster with a
> shared clock within cluster.
Yeah, that had always been the issue. People probably tried to get a
cluster {} block as well to simplify that but there were some objections
to it as well, though not sure what happened to that stuff..
^ permalink raw reply
* [PATCH] ARM: imx6: fix SMP compilation again
From: Shawn Guo @ 2014-07-23 5:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6831797.zmrgHS8Arb@wuerfel>
On Tue, Jul 22, 2014 at 08:52:58PM +0200, Arnd Bergmann wrote:
> On Tuesday 22 July 2014 22:52:57 Shawn Guo wrote:
> > On Tue, Jul 22, 2014 at 04:37:55PM +0200, Arnd Bergmann wrote:
> > > On Tuesday 22 July 2014 21:48:16 Shawn Guo wrote:
> > > > I tried both mainline and -next tree. I really need some help to
> > > > reproduce the error first.
> > >
> > > My branch is at git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git
> > > in the randconfig-next branch. Sorry for the inconvenience.
> >
> > Okay, I can see the error on your branch with the fixing patch reverted.
> >
> > >
> > > > > arch/arm/mach-imx/built-in.o: In function `v7_secondary_startup':
> > > > > :(.text+0x5124): undefined reference to `v7_invalidate_l1'
> > > > >
> > > > > This puts the code inside of an "ifdef CONFIG_SMP" to hopefully
> > > >
> > > > The code says "ifdef CONFIG_SOC_IMX6"?
> > >
> > > It seems I'm having a bad day. I'll fix it up.
> >
> > With that fixed up,
> >
> > Acked-by: Shawn Guo <shawn.guo@freescale.com>
> >
> > Or let me know if you expect me to handle the patch.
> >
>
> If you don't mind, just put it into your tree. I'm currently in the
> middle of going through my older patches and don't want to lose this one.
Okay, applied after fixing up the commit log.
Shawn
^ permalink raw reply
* [PATCH v2] cpufreq: tests: Providing cpufreq regression test
From: Viresh Kumar @ 2014-07-23 5:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405926154-27214-1-git-send-email-l.majewski@samsung.com>
Hi Lukasz,
I haven't replied yet as I wanted to see what the general feed of Rafael
is going to be :)
As this is something new and wasn't sure if we really want this..
On 21 July 2014 12:32, Lukasz Majewski <l.majewski@samsung.com> wrote:
> This commit adds first regression test "cpufreq_freq_test.sh" for the
> cpufreq subsystem.
That's not enough, Tell us why we should continue reading this mail..
> Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
>
> ---
> Changes for v2:
> - Replace *_PATCH with *_PATH for variables names
> - Corrected mistakes in the README file
> - Providing detailed explanation of the patch in the README file
> ---
> drivers/cpufreq/tests/README | 33 +++++++
> drivers/cpufreq/tests/cpufreq_freq_test.sh | 149 +++++++++++++++++++++++++++++
Probably a better place would be tools/power/cpufreq/
@Rafael?
> 2 files changed, 182 insertions(+)
> create mode 100644 drivers/cpufreq/tests/README
> create mode 100755 drivers/cpufreq/tests/cpufreq_freq_test.sh
>
> diff --git a/drivers/cpufreq/tests/README b/drivers/cpufreq/tests/README
> new file mode 100644
> index 0000000..3e9cd80
> --- /dev/null
> +++ b/drivers/cpufreq/tests/README
> @@ -0,0 +1,33 @@
> +This file contains list of cpufreq's available regression tests with a short
> +usage description.
> +
> +1. cpufreq_freq_test.sh
> +
> +Description:
> +------------
> +This script is supposed to test if cpufreq attributes exported by sysfs are
> +exposing correct values.
> +
> +To achieve this goal it saves the current governor and changes it to
> +"performance". Afterwards, it reads the "scaling_available_frequencies"
> +property. With the list of supported frequencies it is able to enforce each of
> +them by writing to "scaling_max_freq" attribute. To make the test more reliable
> +a superfluous load with gzip is created to be sure that we are running with
> +highest possible frequency. This high load is regulated with the 'sleep'
> +duration. After this time the "cpufreq_cur_freq" is read and compared with the
> +original value. As the last step the original governor is restored.
I couldn't make out the purpose of this test and why we need it. How do
we ensure that "cpufreq attributes exported by sysfs are exposing
correct values"?
And actually what do we mean by this statement even? What kind of errors can
be there in exposing these values.
I want to understand the purpose of this script very clearly first and then only
will look at the details.
^ permalink raw reply
* [linux-sunxi] GSoC 2014 #1 status report - Improving Allwinner SoC support
From: Chris Moore @ 2014-07-23 5:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v679RqNj4FhT=T5Wx64My6ckDD0Eeq_5aVPh6zz9ei8+rQ@mail.gmail.com>
Le 22/07/2014 12:22, Chen-Yu Tsai a ?crit :
> So the user manual says that 24 bit samples should be right justified,
> or in the most significant bytes.
I understand "right justified" to mean "in the *least* significant bits".
Cheers,
Chris
^ permalink raw reply
* [linux-sunxi] GSoC 2014 #1 status report - Improving Allwinner SoC support
From: Chen-Yu Tsai @ 2014-07-23 5:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <53CF4503.9010000@free.fr>
On Wed, Jul 23, 2014 at 1:15 PM, Chris Moore <moore@free.fr> wrote:
> Le 22/07/2014 12:22, Chen-Yu Tsai a ?crit :
>
>> So the user manual says that 24 bit samples should be right justified,
>> or in the most significant bytes.
>
> I understand "right justified" to mean "in the *least* significant bits".
Ah yes. Pardon me. Sticking to "most significant bits" is better. :)
ChenYu
^ permalink raw reply
* [PATCH 1/1] ASoC: sirf-usp: Fixed a bug for playback and capture work at the same time
From: Rongjun Ying @ 2014-07-23 5:19 UTC (permalink / raw)
To: linux-arm-kernel
1. The startup function invoked when the playback and capture.
If start playback when capturing, the registers are re-initinitialised.
That cause the playback fail. So move the startup code into runtime resume.
2. Modified: If non RUNTIME_PM support, the probe need enable clock and
initinitialise registers.
3. Refine code.
Signed-off-by: Rongjun Ying <rongjun.ying@csr.com>
---
sound/soc/sirf/sirf-usp.c | 54 +++++++++++++++++++++++------------------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
index 9693bc2..3a73037 100644
--- a/sound/soc/sirf/sirf-usp.c
+++ b/sound/soc/sirf/sirf-usp.c
@@ -103,11 +103,8 @@ static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
return 0;
}
-static int sirf_usp_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static void sirf_usp_i2s_init(struct sirf_usp *usp)
{
- struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai);
-
/* Configure RISC mode */
regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE,
USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL);
@@ -119,19 +116,16 @@ static int sirf_usp_i2s_startup(struct snd_pcm_substream *substream,
regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0);
regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0);
- regmap_write(usp->regmap, USP_RX_FRAME_CTRL, USP_SINGLE_SYNC_MODE);
-
- regmap_write(usp->regmap, USP_TX_FRAME_CTRL, USP_TXC_SLAVE_CLK_SAMPLE);
-
/* Configure Mode2 register */
regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) |
- (0 << USP_TXD_DELAY_LEN_OFFSET));
+ (0 << USP_TXD_DELAY_LEN_OFFSET) |
+ USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE);
/* Configure Mode1 register */
regmap_write(usp->regmap, USP_MODE1,
USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING |
USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 |
- USP_TX_UFLOW_REPEAT_ZERO);
+ USP_TX_UFLOW_REPEAT_ZERO | USP_CLOCK_MODE_SLAVE);
/* Configure RX DMA IO Control register */
regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0);
@@ -155,8 +149,6 @@ static int sirf_usp_i2s_startup(struct snd_pcm_substream *substream,
/* Congiure TX FIFO Level Check register */
regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK,
TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04));
-
- return 0;
}
static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -204,23 +196,19 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL,
USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK
- | USP_TXC_SHIFTER_LEN_MASK,
+ | USP_TXC_SHIFTER_LEN_MASK | USP_TXC_SLAVE_CLK_SAMPLE,
((data_len - 1) << USP_TXC_DATA_LEN_OFFSET)
| ((frame_len - 1) << USP_TXC_FRAME_LEN_OFFSET)
- | ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET));
+ | ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET)
+ | USP_TXC_SLAVE_CLK_SAMPLE);
else
regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL,
USP_RXC_DATA_LEN_MASK | USP_RXC_FRAME_LEN_MASK
- | USP_RXC_SHIFTER_LEN_MASK,
+ | USP_RXC_SHIFTER_LEN_MASK | USP_SINGLE_SYNC_MODE,
((data_len - 1) << USP_RXC_DATA_LEN_OFFSET)
| ((frame_len - 1) << USP_RXC_FRAME_LEN_OFFSET)
- | ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET));
-
- regmap_update_bits(usp->regmap, USP_MODE1,
- USP_CLOCK_MODE_SLAVE, USP_CLOCK_MODE_SLAVE);
- regmap_update_bits(usp->regmap, USP_MODE2,
- USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE,
- USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE);
+ | ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET)
+ | USP_SINGLE_SYNC_MODE);
return 0;
}
@@ -253,7 +241,6 @@ static int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
}
static const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = {
- .startup = sirf_usp_i2s_startup,
.trigger = sirf_usp_pcm_trigger,
.set_fmt = sirf_usp_pcm_set_dai_fmt,
.hw_params = sirf_usp_pcm_hw_params,
@@ -282,7 +269,6 @@ static struct snd_soc_dai_driver sirf_usp_pcm_dai = {
.ops = &sirf_usp_pcm_dai_ops,
};
-#ifdef CONFIG_PM
static int sirf_usp_pcm_runtime_suspend(struct device *dev)
{
struct sirf_usp *usp = dev_get_drvdata(dev);
@@ -293,9 +279,15 @@ static int sirf_usp_pcm_runtime_suspend(struct device *dev)
static int sirf_usp_pcm_runtime_resume(struct device *dev)
{
struct sirf_usp *usp = dev_get_drvdata(dev);
- return clk_prepare_enable(usp->clk);
+ int ret;
+ ret = clk_prepare_enable(usp->clk);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+ sirf_usp_i2s_init(usp);
+ return 0;
}
-#endif
#ifdef CONFIG_PM_SLEEP
static int sirf_usp_pcm_suspend(struct device *dev)
@@ -369,6 +361,11 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = sirf_usp_pcm_runtime_resume(&pdev->dev);
+ if (ret)
+ return ret;
+ }
ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component,
&sirf_usp_pcm_dai, 1);
@@ -381,7 +378,10 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev)
static int sirf_usp_pcm_remove(struct platform_device *pdev)
{
- pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev))
+ sirf_usp_pcm_runtime_suspend(&pdev->dev);
+ else
+ pm_runtime_disable(&pdev->dev);
return 0;
}
--
1.9.3
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.
^ permalink raw reply related
* [PATCH 00/14] arm64: eBPF JIT compiler
From: Z Lim @ 2014-07-23 5:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMEtUuyC+MykPDO0ghTc=oex7KPLEy=BLRgWBdW+qJY7JXQmDQ@mail.gmail.com>
On Mon, Jul 21, 2014 at 8:49 AM, Alexei Starovoitov <ast@plumgrid.com> wrote:
> On Mon, Jul 21, 2014 at 2:16 AM, Will Deacon <will.deacon@arm.com> wrote:
[...]
>>> This series applies against net-next and is tested working
>>> with lib/test_bpf on ARMv8 Foundation Model.
>>
>> Looks like it works on my Juno board too, so:
>>
>> Acked-by: Will Deacon <will.deacon@arm.com>
>>
>> for the series.
Thanks Will! I've added your acked-by to the entire series, also
tweaked 14/14's commit log to indicate that it's been tested on Juno
as well.
>>
>> It's a bit late for 3.17 now, so I guess we'll queue this for 3.18 (which
>> also means the dependency on -next isn't an issue). Perhaps you could repost
>> around -rc3?
>
> Thanks for testing! Nice to see it working on real hw.
> I'm not sure why you're proposing a 4+ week delay. The patches
> will rot instead of getting used and tested. Imo it makes sense to
> get them into net-next now for 3.17.
> JIT is disabled by sysctl by default anyway.
Hmm... if net-next is still open, and David is willing to pull in this
series, I share Alexei's opinion -- don't see why a delay is
necessary. David, any chance of pulling this series into net-next for
3.17?
BTW, I also tried merging
'git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
for-next/core' with this series. The example merge is available at
'https://github.com/zlim/linux.git arm64/bpf-merge'. The merge
conflict resolution is really trivial:
--------8<--------
diff --cc arch/arm64/Kconfig
index 7534a80a,ce6e733..c165c91
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@@ -32,8 -33,8 +34,9 @@@ config ARM6
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK
- select HAVE_C_RECORDMCOUNT
+ select HAVE_BPF_JIT
+ select HAVE_C_RECORDMCOUNT
+ select HAVE_CC_STACKPROTECTOR
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG
-------->8--------
Anyway, here's an updated branch (with Will's acks, commit log tweak
noting Will's testing on real hardware, rebase on net-next). I can
repost entire patch series if needed.
----------------------------------------------------------------
The following changes since commit 52c4f0ec662bbf02f1b0bcb311a48af2c8e5ee89:
drivers: net: cpsw: add support to dump ALE table via ethtool
register dump (2014-07-22 19:58:25 -0700)
are available in the git repository at:
https://github.com/zlim/linux.git arm64/bpf
for you to fetch changes up to 533f668ff3e8d69f22c6e5432e0eb1005f2e8970:
arm64: eBPF JIT compiler (2014-07-22 21:52:09 -0700)
----------------------------------------------------------------
^ permalink raw reply
* [PATCH] Input: s3c2410_ts: Move to clk_prepare_enable/clk_disable_unprepare
From: Dmitry Torokhov @ 2014-07-23 6:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2138540.gOK28iFQ6r@vasilykh-desktop-i5>
Hi Vasily,
On Wed, Jul 09, 2014 at 12:13:41PM +0300, Vasily Khoruzhick wrote:
> On 8 July 2014 18:00:49 Dmitry Torokhov wrote:
>
> Hi Dmitry,
>
> > >
> > > - clk_disable(ts.clock);
> > > + clk_disable_unprepare(ts.clock);
> >
> > Do we really need to unprepare on suspend? Why simply disabling is not
> > enough here?
>
> You're right, disabling should be enough here. I'll resend a patch after
> testing on a hardware.
I ended up cutting out suspend/resume parts and applying.
Thanks.
--
Dmitry
^ permalink raw reply
* Issue found in Armada 370: "No buffer space available" error during continuous ping
From: Willy Tarreau @ 2014-07-23 6:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAB8gEUtmgwfWcuoYZ-wDwHVmzHN0WyOQD9oEOGAZ_gJfbPUm-g@mail.gmail.com>
Hi Maggie,
On Tue, Jul 22, 2014 at 07:24:35PM -0700, Maggie Mae Roxas wrote:
> Hi Willy,
> Good day.
>
> > OK so clearly the issue must be found.
>
> Actually we have 2 products using Armada 370.
> One has only 1 ethernet port, so it is expected to act as Client only.
> The other one has 2 ethernet ports, so it's more router-like.
>
> For the product with one port, we have checked the combination patch
> and it seems like Tx IRQ is increasing so it's OK. We checked this via
> /proc/interrupts and mvneta's value there changed from 500000+ to
> around 900000+ after we perform a 10-iteration iperf to the server.
> The throughput is also OK, we're getting around 850Mbits when we use a
> 1Gbit connection, which is roughly just the same as what we've been
> experiencing when we're still using 3.10.x (even 3.2.x).
OK.
> As for the other product with two ports, we do expect that we might be
> encountering the slow performance you mentioned.
> But we are not focusing on this project yet so once it's active again,
> I'll let you know.
>
> > Just thinking about something, do you have a custom boot loader ?
> > It would be possible that in our case, the Tx IRQ works only because some
> > obscure or undocumented bits are set by the boot loader and that in your
> > case it's not pre-initialized.
>
> We are indeed using a "custom" boot loader.
> We are using Marvell u-boot 2014_T1.1 (latest QA release, I think).
> We applied some patches to memory (since we have 1Gb DDR), some bits
> and pieces for the interfaces we're going to support and not to
> support, and of course our own environment variables.
> As for the DDR memory/register patches, they came directly from our
> Marvell contact.
>
> But with what I mentioned above, I think our Tx interrupt is working...?
Yes, seems so.
> BTW, for both products we've designed from Armada 370 RD, we didn't
> use a switch. So we removed all switch-related codes in the boot
> loader.
> I'm not sure if not having switch affects the behavior?
I have no idea, I remember that this code is deeply burried into the
original neta code. There was also a large code for the network
classifier and something like buffer management in the original
Marvell's driver if my memory serves me correctly, I have no idea
if these ones set up anything special.
> How about you? May I know what boot loader you are using?
Just the original ones. I have a mirabox with its original boot loader :
U-Boot 2009.08 (Sep 16 2012 - 22:50:06)Marvell version: 1.1.2 NQ
U-Boot Addressing:
Code: 00600000:006AFFF0
BSS: 006F8E40
Stack: 0x5fff70
PageTable: 0x8e0000
Heap address: 0x900000:0xe00000
Board: DB-88F6710-BP
SoC: MV6710 A1
CPU: Marvell PJ4B v7 UP (Rev 1) LE
CPU @ 1200Mhz, L2 @ 600Mhz
DDR @ 600Mhz, TClock @ 200Mhz
DDR 16Bit Width, FastPath Memory Access
PEX 0: Detected No Link.
PEX 1: Root Complex Interface, Detected Link X1
DRAM: 1 GB
CS 0: base 0x00000000 size 512 MB
CS 1: base 0x20000000 size 512 MB
Addresses 14M - 0M are saved for the U-Boot usage.
NAND: 1024 MiB
Bad block table found at page 262016, version 0x01
Bad block table found at page 261888, version 0x01
FPU not initialized
USB 0: Host Mode
USB 1: Host Mode
Modules/Interfaces Detected:
RGMII0 Phy
RGMII1 Phy
PEX0 (Lane 0)
PEX1 (Lane 1)
phy16= 72
phy16= 72
MMC: MRVL_MMC: 0
Net: egiga0 [PRIME], egiga1
Hit any key to stop autoboot: 0
> > LTS would probably even interest your customer as it's an LTS version.
> > In this case, always pick the most recent one (3.14.12 today). You may
> > even be interested in 3.15.6 which contains another phy fix supposed to
> > fix cd71e2, but if you're saying that it doesn't change anything for you
> > I guess it will have no effet (might be worth testing for the purpose of
> > helping troubleshooting though).
>
> Thank you for this advise, we'll take note of this.
> We plan to stick on using LTS from now on, as much as possible.
>
> > OK. I still have a hard time imagining how hardware itself could prevent
> > an IRQ from being delivered from a NIC which is located inside the SoC,
> > but there must be an explanation somewhere :-/
> I also would like to know how. :-/
> But maybe it's our difference in boot loader as you speculated.
I think we could try to dump all of our respective mvneta registers and
compare them, though I have very little time for this today. And if it
comes from extra SoC functions like buffer management or network classifier,
I have no idea how they work nor what to dump :-/
Regards,
Willy
^ permalink raw reply
* [PATCH 0/3] Deterministic UART numbering on Samsung SoCs
From: Daniel Drake @ 2014-07-23 6:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140709142333.503a9e39@alan.etchedpixels.co.uk>
On Wed, Jul 9, 2014 at 2:23 PM, One Thousand Gnomes
<gnomes@lxorguk.ukuu.org.uk> wrote:
>> I like the sound of going to the standard ttyS notation and only
>> providing ports for ones that exist, but is this userspace-visible
>
> ttyS is 8250 compatible UARTS.
>
> If the Samsung is not an 8250 compatible UART then it doesn't belong as
> ttyS from the kernel perspective.
OK, thanks for pointing that out.
So we stick with the ttySAC namespace. And by doing that, and sticking
to the existing and documented behaviour, it seems like we have
already addressed Russells's concern:
> The problem you're raising is very much the same problem you have when
> there are multiple USB serial devices connected to the machine - you
> just get a bunch of /dev/ttyUSB* devices which are unordered (they can
> change on each boot, or change order if you disconnect and reconnect
> them.)
In this case, we have a dedicated namespace and the path information
is already fully encoded in the device name. The order and number of
ports are fixed, they can't be disconnected and reconnected. There is
no real risk of an additional serial controller driver coming to play
in the ttySAC namespace.
So I think Tomasz's approach is good - although I haven't looked at
the code in detail.
Thanks
Daniel
^ permalink raw reply
* [PATCH v3 0/2] This series adds support for RK3288 SoC integrated PWM
From: Caesar Wang @ 2014-07-23 6:38 UTC (permalink / raw)
To: linux-arm-kernel
This patch will make applying on the top of Beniamino's submission,
the Beniamino's submission come from [1].
[1]:
https://git.kernel.org/cgit/linux/kernel/git/thierry.reding/linux-pwm.git/log/?h=for-next
Beniamino's submission won't be used from genenation Rockchip SoCs.
So I have to add the new pwm for next genenation Rockchip SoCs.
Tested on RK3288 SDK board.
Changes in v3:
* address comments from Thierry Reding:
- fix PWM document deccribes.
- add a description for [PATCH v3 2/2].
- renamed the PWM registers
- Changed in rockchip_pwm_data struct
- remove the devm_ioremap(),fixed in lcdc driver.
Changes in v2:
* address comments from Beniamino Galvani:
- remove #include <linux/of_address.h>.
- of_iomap be removed,and devm_ioremap replace it.
- remove a line no be used.
Caesar Wang (2):
pwm: rockchip: document RK3288 SoC compatible
pwm: rockchip: Added to support for RK3288 SoC
.../devicetree/bindings/pwm/pwm-rockchip.txt | 5 +-
drivers/pwm/pwm-rockchip.c | 141 ++++++++++++++++++---
2 files changed, 126 insertions(+), 20 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH v3 1/2] pwm: rockchip: document RK3288 SoC compatible
From: Caesar Wang @ 2014-07-23 6:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1406097521-6457-1-git-send-email-caesar.wang@rock-chips.com>
Document new compatible for PWM founding on RK3288 SoC
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
index 3182126..2b7c109 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
@@ -1,7 +1,10 @@
Rockchip PWM controller
Required properties:
- - compatible: should be "rockchip,rk2928-pwm"
+ - compatible: should be "rockchip,<name>-pwm"
+ "rockchip,rk2928-pwm": found on RK29XX,RK3066 and RK3188 SoCs
+ "rockchip,rk3288-pwm": found on RK3288 SoC
+ "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
- reg: physical base address and length of the controller's registers
- clocks: phandle and clock specifier of the PWM reference clock
- #pwm-cells: should be 2. See pwm.txt in this directory for a
--
1.9.1
^ permalink raw reply related
* [PATCH v3 2/2] pwm: rockchip: Added to support for RK3288 SoC
From: Caesar Wang @ 2014-07-23 6:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1406097521-6457-1-git-send-email-caesar.wang@rock-chips.com>
This patch added to support the PWM controller found on
RK3288 SoC.
Signed-off-by: Caesar Wang <caesar.wang@rock-chips.com>
---
drivers/pwm/pwm-rockchip.c | 141 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 122 insertions(+), 19 deletions(-)
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index eec2145..8d72a98 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -2,6 +2,7 @@
* PWM driver for Rockchip SoCs
*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ * Copyright (C) 2014 Caesar Wang <caesar.wang@rock-chips.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -12,6 +13,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/time.h>
@@ -25,17 +27,89 @@
#define PRESCALER 2
+#define PWM_ENABLE (1 << 0)
+#define PWM_CONTINUOUS (1 << 1)
+#define PWM_DUTY_POSITIVE (1 << 3)
+#define PWM_INACTIVE_NEGATIVE (0 << 4)
+#define PWM_OUTPUT_LEFT (0 << 5)
+#define PWM_LP_DISABLE (0 << 8)
+
struct rockchip_pwm_chip {
struct pwm_chip chip;
struct clk *clk;
+ const struct rockchip_pwm_data *data;
void __iomem *base;
};
+struct rockchip_pwm_regs {
+ unsigned long duty;
+ unsigned long period;
+ unsigned long cntr;
+ unsigned long ctrl;
+};
+
+struct rockchip_pwm_data {
+ struct rockchip_pwm_regs regs;
+ unsigned int prescaler;
+
+ void (*set_enable)(struct pwm_chip *chip, bool enable);
+};
+
static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
{
return container_of(c, struct rockchip_pwm_chip, chip);
}
+static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip, bool enable)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 val = 0;
+ u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
+
+ val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+
+ if (enable)
+ val |= enable_conf;
+ else
+ val &= ~enable_conf;
+
+ writel_relaxed(val, pc->base + pc->data->regs.ctrl);
+}
+
+static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 val = 0;
+ u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS | PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
+
+ val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+
+ if (enable)
+ val |= enable_conf;
+ else
+ val &= ~enable_conf;
+
+ writel_relaxed(val, pc->base + pc->data->regs.ctrl);
+}
+
+static void rockchip_pwm_set_enable_vop(struct pwm_chip *chip, bool enable)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 val = 0;
+ u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS | PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
+
+ val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+
+ if (enable)
+ val |= enable_conf;
+ else
+ val &= ~enable_conf;
+
+ writel_relaxed(val, pc->base + pc->data->regs.ctrl);
+}
+
static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
@@ -52,20 +126,20 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* default prescaler value for all practical clock rate values.
*/
div = clk_rate * period_ns;
- do_div(div, PRESCALER * NSEC_PER_SEC);
+ do_div(div, pc->data->prescaler * NSEC_PER_SEC);
period = div;
div = clk_rate * duty_ns;
- do_div(div, PRESCALER * NSEC_PER_SEC);
+ do_div(div, pc->data->prescaler * NSEC_PER_SEC);
duty = div;
ret = clk_enable(pc->clk);
if (ret)
return ret;
- writel(period, pc->base + PWM_LRC);
- writel(duty, pc->base + PWM_HRC);
- writel(0, pc->base + PWM_CNTR);
+ writel(period, pc->base + pc->data->regs.period);
+ writel(duty, pc->base + pc->data->regs.duty);
+ writel(0, pc->base + pc->data->regs.cntr);
clk_disable(pc->clk);
@@ -76,15 +150,12 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
int ret;
- u32 val;
ret = clk_enable(pc->clk);
if (ret)
return ret;
- val = readl_relaxed(pc->base + PWM_CTRL);
- val |= PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
- writel_relaxed(val, pc->base + PWM_CTRL);
+ pc->data->set_enable(chip, true);
return 0;
}
@@ -92,11 +163,8 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
- u32 val;
- val = readl_relaxed(pc->base + PWM_CTRL);
- val &= ~(PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN);
- writel_relaxed(val, pc->base + PWM_CTRL);
+ pc->data->set_enable(chip, false);
clk_disable(pc->clk);
}
@@ -108,12 +176,52 @@ static const struct pwm_ops rockchip_pwm_ops = {
.owner = THIS_MODULE,
};
+static const struct rockchip_pwm_data pwm_data_v1 = {
+ .regs.duty = PWM_HRC,
+ .regs.period = PWM_LRC,
+ .regs.cntr = PWM_CNTR,
+ .regs.ctrl = PWM_CTRL,
+ .prescaler = PRESCALER,
+ .set_enable = rockchip_pwm_set_enable_v1,
+};
+
+static const struct rockchip_pwm_data pwm_data_v2 = {
+ .regs.duty = PWM_LRC,
+ .regs.period = PWM_HRC,
+ .regs.cntr = PWM_CNTR,
+ .regs.ctrl = PWM_CTRL,
+ .prescaler = PRESCALER-1,
+ .set_enable = rockchip_pwm_set_enable_v2,
+};
+
+static const struct rockchip_pwm_data pwm_data_vop = {
+ .regs.duty = PWM_LRC,
+ .regs.period = PWM_HRC,
+ .regs.cntr = PWM_CTRL,
+ .regs.ctrl = PWM_CNTR,
+ .prescaler = PRESCALER-1,
+ .set_enable = rockchip_pwm_set_enable_vop,
+};
+
+static const struct of_device_id rockchip_pwm_dt_ids[] = {
+ { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
+ { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
+ { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
+
static int rockchip_pwm_probe(struct platform_device *pdev)
{
+ const struct of_device_id *id;
struct rockchip_pwm_chip *pc;
struct resource *r;
int ret;
+ id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
+ if (!id)
+ return -EINVAL;
+
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
@@ -133,6 +241,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pc);
+ pc->data = id->data;
pc->chip.dev = &pdev->dev;
pc->chip.ops = &rockchip_pwm_ops;
pc->chip.base = -1;
@@ -156,12 +265,6 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
return pwmchip_remove(&pc->chip);
}
-static const struct of_device_id rockchip_pwm_dt_ids[] = {
- { .compatible = "rockchip,rk2928-pwm" },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
-
static struct platform_driver rockchip_pwm_driver = {
.driver = {
.name = "rockchip-pwm",
--
1.9.1
^ permalink raw reply related
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Thierry Reding @ 2014-07-23 6:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohpomQthJ_XE-HhzW07Q4aVtxQVy97iaL0Vy6Q4Lhw22A=VA@mail.gmail.com>
On Wed, Jul 23, 2014 at 10:14:44AM +0530, Viresh Kumar wrote:
> On 21 July 2014 21:09, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
>
> > diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> > index 7364a53..df3c73e 100644
> > --- a/drivers/cpufreq/Kconfig.arm
> > +++ b/drivers/cpufreq/Kconfig.arm
> > @@ -244,6 +244,7 @@ config ARM_SPEAR_CPUFREQ
> > config ARM_TEGRA_CPUFREQ
> > bool "TEGRA CPUFreq support"
> > depends on ARCH_TEGRA
> > + depends on GENERIC_CPUFREQ_CPU0
>
> Wouldn't this also disturb the existing cpufreq driver for earlier
> tegra platforms? i.e. we don't need cpufreq-cpu0 for them
> atleast as of now.
Perhaps this should be "select" rather than "depends on"?
> > +static int tegra124_cpufreq_probe(struct platform_device *pdev)
> > +{
> > + int ret;
> > +
> > + cpu_dev = get_cpu_device(0);
> > + if (!cpu_dev)
> > + return -ENODEV;
> > +
>
> Shouldn't we do a of_node_get() here?
I think this would need to be get_device() since it's the struct device
that's being used subsequently.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140723/fd38e09f/attachment.sig>
^ permalink raw reply
* [PATCH v1 2/3] mtd: hisilicon: add a new nand controller driver for hisilicon hip04 Soc
From: Zhou Wang @ 2014-07-23 6:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405421906-660-3-git-send-email-wangzhou.bry@gmail.com>
On 2014?07?15? 18:58, Zhou Wang wrote:
> Signed-off-by: Zhou Wang <wangzhou.bry@gmail.com>
> ---
> drivers/mtd/nand/Kconfig | 5 +
> drivers/mtd/nand/Makefile | 1 +
> drivers/mtd/nand/hisi_nand.c | 836 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 842 insertions(+)
> create mode 100644 drivers/mtd/nand/hisi_nand.c
>
Hi David Woodhouse and Brian Norris,
Is there anything I should modify about this NAND controller driver? It
would be appreciated that I could get some comments from you.
Best regarts,
Zhou
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 90ff447..253f8c8 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -510,4 +510,9 @@ config MTD_NAND_XWAY
> Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
> to the External Bus Unit (EBU).
>
> +config MTD_NAND_HISI
> + tristate "Support for NAND controller on Hisilicon SoC"
> + help
> + Enables support for NAND controller on Hisilicon SoC.
> +
> endif # MTD_NAND
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index 542b568..d0881cf 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -49,5 +49,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
> obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
> obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
> obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
> +obj-$(CONFIG_MTD_NAND_HISI) += hisi_nand.o
>
> nand-objs := nand_base.o nand_bbt.o
> diff --git a/drivers/mtd/nand/hisi_nand.c b/drivers/mtd/nand/hisi_nand.c
> new file mode 100644
> index 0000000..c5142bb
> --- /dev/null
> +++ b/drivers/mtd/nand/hisi_nand.c
> @@ -0,0 +1,836 @@
> +/*
> + * Hisilicon NAND Flash controller driver
> + *
> + * Copyright ? 2012-2014 HiSilicon Technologies Co., Ltd.
> + * http://www.hisilicon.com
> + *
> + * Author: Zhou Wang <wangzhou.bry@gmail.com>
> + * The initial developer of the original code is Zhiyong Cai
> + * <caizhiyong@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +#include <linux/of.h>
> +#include <linux/of_mtd.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/sizes.h>
> +#include <linux/clk.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include <linux/mtd/partitions.h>
> +
> +#define HINFC504_MAX_CHIP (4)
> +#define HINFC504_W_LATCH (5)
> +#define HINFC504_R_LATCH (7)
> +#define HINFC504_RW_LATCH (3)
> +
> +#define HINFC504_NFC_TIMEOUT (2 * HZ)
> +#define HINFC504_NFC_DMA_TIMEOUT (5 * HZ)
> +#define HINFC504_CHIP_DELAY (25)
> +
> +#define HINFC504_REG_BASE_ADDRESS_LEN (0x100)
> +#define HINFC504_BUFFER_BASE_ADDRESS_LEN (2048 + 128)
> +
> +#define HINFC504_ADDR_CYCLE_MASK 0x4
> +
> +#define HINFC504_CON 0x00
> +#define HINFC504_CON_OP_MODE_NORMAL (1U << 0)
> +#define HINFC504_CON_PAGEISZE_SHIFT (1)
> +#define HINFC504_CON_PAGESIZE_MASK (0x07)
> +#define HINFC504_CON_BUS_WIDTH (1U << 4)
> +#define HINFC504_CON_READY_BUSY_SEL (1U << 8)
> +#define HINFC504_CON_ECCTYPE_SHIFT (9)
> +#define HINFC504_CON_ECCTYPE_MASK (0x07)
> +
> +#define HINFC504_PWIDTH 0x04
> +#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
> + ((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
> +
> +#define HINFC504_CMD 0x0C
> +#define HINFC504_ADDRL 0x10
> +#define HINFC504_ADDRH 0x14
> +#define HINFC504_DATA_NUM 0x18
> +
> +#define HINFC504_OP 0x1C
> +#define HINFC504_OP_READ_DATA_EN (1U << 1)
> +#define HINFC504_OP_WAIT_READY_EN (1U << 2)
> +#define HINFC504_OP_CMD2_EN (1U << 3)
> +#define HINFC504_OP_WRITE_DATA_EN (1U << 4)
> +#define HINFC504_OP_ADDR_EN (1U << 5)
> +#define HINFC504_OP_CMD1_EN (1U << 6)
> +#define HINFC504_OP_NF_CS_SHIFT (7)
> +#define HINFC504_OP_NF_CS_MASK (3)
> +#define HINFC504_OP_ADDR_CYCLE_SHIFT (9)
> +#define HINFC504_OP_ADDR_CYCLE_MASK (7)
> +
> +#define HINFC504_STATUS 0x20
> +#define HINFC504_READY (1U << 0)
> +
> +#define HINFC504_INTEN 0x24
> +#define HINFC504_INTEN_DMA (1U << 9)
> +#define HINFC504_INTEN_UE (1U << 6)
> +#define HINFC504_INTEN_CE (1U << 5)
> +
> +#define HINFC504_INTS 0x28
> +#define HINFC504_INTS_DMA (1U << 9)
> +#define HINFC504_INTS_UE (1U << 6)
> +#define HINFC504_INTS_CE (1U << 5)
> +
> +#define HINFC504_INTCLR 0x2C
> +#define HINFC504_INTCLR_DMA (1U << 9)
> +#define HINFC504_INTCLR_UE (1U << 6)
> +#define HINFC504_INTCLR_CE (1U << 5)
> +
> +#define HINFC504_ECC_STATUS 0x5C
> +#define HINFC504_ECC_1_BIT_SHIFT 16
> +#define HINFC504_ECC_16_BIT_SHIFT 12
> +
> +#define HINFC504_DMA_CTRL 0x60
> +#define HINFC504_DMA_CTRL_DMA_START (1U << 0)
> +#define HINFC504_DMA_CTRL_WE (1U << 1)
> +#define HINFC504_DMA_CTRL_DATA_AREA_EN (1U << 2)
> +#define HINFC504_DMA_CTRL_OOB_AREA_EN (1U << 3)
> +#define HINFC504_DMA_CTRL_BURST4_EN (1U << 4)
> +#define HINFC504_DMA_CTRL_BURST8_EN (1U << 5)
> +#define HINFC504_DMA_CTRL_BURST16_EN (1U << 6)
> +#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT (7)
> +#define HINFC504_DMA_CTRL_ADDR_NUM_MASK (1)
> +#define HINFC504_DMA_CTRL_CS_SHIFT (8)
> +#define HINFC504_DMA_CTRL_CS_MASK (0x03)
> +
> +#define HINFC504_DMA_ADDR_DATA 0x64
> +#define HINFC504_DMA_ADDR_OOB 0x68
> +
> +#define HINFC504_DMA_LEN 0x6C
> +#define HINFC504_DMA_LEN_OOB_SHIFT (16)
> +#define HINFC504_DMA_LEN_OOB_MASK (0xFFF)
> +
> +#define HINFC504_DMA_PARA 0x70
> +#define HINFC504_DMA_PARA_DATA_RW_EN (1U << 0)
> +#define HINFC504_DMA_PARA_OOB_RW_EN (1U << 1)
> +#define HINFC504_DMA_PARA_DATA_EDC_EN (1U << 2)
> +#define HINFC504_DMA_PARA_OOB_EDC_EN (1U << 3)
> +#define HINFC504_DMA_PARA_DATA_ECC_EN (1U << 4)
> +#define HINFC504_DMA_PARA_OOB_ECC_EN (1U << 5)
> +
> +#define HINFC_VERSION 0x74
> +#define HINFC504_LOG_READ_ADDR 0x7C
> +#define HINFC504_LOG_READ_LEN 0x80
> +
> +#define HINFC504_NANDINFO_LEN 0x10
> +
> +struct hinfc_host {
> + struct nand_chip chip;
> + struct mtd_info mtd;
> + struct device *dev;
> + void __iomem *iobase;
> + struct completion cmd_complete;
> + unsigned int offset;
> + unsigned int command;
> + int chipselect;
> + unsigned int addr_cycle;
> + unsigned int addr_value[2];
> + unsigned int cache_addr_value[2];
> + char *buffer;
> + dma_addr_t dma_buffer;
> + dma_addr_t dma_oob;
> + int version;
> + unsigned int ecc_bits;
> + unsigned int irq_status; /* interrupt status */
> +};
> +
> +static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
> +{
> + return readl(host->iobase + reg);
> +}
> +
> +static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
> + unsigned int reg)
> +{
> + writel(value, host->iobase + reg);
> +}
> +
> +static void wait_controller_finished(struct hinfc_host *host)
> +{
> + unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
> + int val;
> +
> + while (time_before(jiffies, timeout)) {
> + val = hinfc_read(host, HINFC504_STATUS);
> + if (host->command == NAND_CMD_ERASE2) {
> + /* nfc is ready */
> + while (!(val & HINFC504_READY)) {
> + usleep_range(500, 1000);
> + val = hinfc_read(host, HINFC504_STATUS);
> + }
> + return;
> + } else {
> + if (val & HINFC504_READY)
> + return;
> + }
> + }
> +
> + /* wait cmd timeout */
> + dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
> +}
> +
> +static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
> +{
> + struct mtd_info *mtd = &host->mtd;
> + struct nand_chip *chip = mtd->priv;
> + unsigned long val;
> + int ret;
> +
> + hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
> + hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
> +
> + if (chip->ecc.mode == NAND_ECC_NONE) {
> + hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
> + << HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
> +
> + hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
> + | HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
> + } else {
> + hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
> + | HINFC504_DMA_PARA_OOB_RW_EN | HINFC504_DMA_PARA_DATA_EDC_EN
> + | HINFC504_DMA_PARA_OOB_EDC_EN | HINFC504_DMA_PARA_DATA_ECC_EN
> + | HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
> + }
> +
> + val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
> + | HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
> + | HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
> + | ((host->addr_cycle == 4 ? 1 : 0)
> + << HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
> + | ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
> + << HINFC504_DMA_CTRL_CS_SHIFT));
> +
> + if (todev)
> + val |= HINFC504_DMA_CTRL_WE;
> +
> + hinfc_write(host, val, HINFC504_DMA_CTRL);
> +
> + init_completion(&host->cmd_complete);
> + ret = wait_for_completion_timeout(&host->cmd_complete,
> + HINFC504_NFC_DMA_TIMEOUT);
> +
> + if (!ret) {
> + dev_err(host->dev, "DMA operation(irq) timeout!\n");
> + /* sanity check */
> + val = hinfc_read(host, HINFC504_DMA_CTRL);
> + if (!(val & HINFC504_DMA_CTRL_DMA_START))
> + dev_err(host->dev, "dma is already done but without irq ACK!");
> + else
> + dev_err(host->dev, "dma is really timeout!");
> + }
> +}
> +
> +static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
> +{
> + host->addr_value[0] &= 0xffff0000;
> +
> + hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
> + hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
> + hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
> + HINFC504_CMD);
> +
> + hisi_nfc_dma_transfer(host, 1);
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
> +{
> + struct mtd_info *mtd = &host->mtd;
> +
> + if ((host->addr_value[0] == host->cache_addr_value[0]) &&
> + (host->addr_value[1] == host->cache_addr_value[1]))
> + return 0;
> +
> + host->addr_value[0] &= 0xffff0000;
> +
> + hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
> + hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
> + hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
> + HINFC504_CMD);
> +
> + hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
> + hinfc_write(host, mtd->writesize + mtd->oobsize,
> + HINFC504_LOG_READ_LEN);
> +
> + hisi_nfc_dma_transfer(host, 0);
> +
> + host->cache_addr_value[0] = host->addr_value[0];
> + host->cache_addr_value[1] = host->addr_value[1];
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
> +{
> + hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
> + hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
> + HINFC504_CMD);
> +
> + hinfc_write(host, HINFC504_OP_WAIT_READY_EN
> + | HINFC504_OP_CMD2_EN
> + | HINFC504_OP_CMD1_EN
> + | HINFC504_OP_ADDR_EN
> + | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
> + << HINFC504_OP_NF_CS_SHIFT)
> + | ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
> + << HINFC504_OP_ADDR_CYCLE_SHIFT),
> + HINFC504_OP);
> +
> + wait_controller_finished(host);
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
> +{
> + hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
> + hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
> + hinfc_write(host, 0, HINFC504_ADDRL);
> +
> + hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
> + | HINFC504_OP_READ_DATA_EN
> + | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
> + << HINFC504_OP_NF_CS_SHIFT)
> + | 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
> +
> + wait_controller_finished(host);
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
> +{
> + hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
> + hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
> + hinfc_write(host, HINFC504_OP_CMD1_EN
> + | HINFC504_OP_READ_DATA_EN
> + | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
> + << HINFC504_OP_NF_CS_SHIFT),
> + HINFC504_OP);
> +
> + wait_controller_finished(host);
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
> +{
> + hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
> +
> + hinfc_write(host, HINFC504_OP_CMD1_EN
> + | ((chipselect & HINFC504_OP_NF_CS_MASK)
> + << HINFC504_OP_NF_CS_SHIFT)
> + | HINFC504_OP_WAIT_READY_EN,
> + HINFC504_OP);
> +
> + wait_controller_finished(host);
> +
> + return 0;
> +}
> +
> +static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + if (chipselect < 0)
> + return;
> +
> + host->chipselect = chipselect;
> +}
> +
> +static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + if (host->command == NAND_CMD_STATUS)
> + return readb(chip->IO_ADDR_R);
> +
> + host->offset++;
> +
> + if (host->command == NAND_CMD_READID)
> + return readb(chip->IO_ADDR_R + host->offset - 1);
> +
> + return readb(host->buffer + host->offset - 1);
> +}
> +
> +static u16 hisi_nfc_read_word(struct mtd_info *mtd)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + host->offset += 2;
> + return readw(host->buffer + host->offset - 2);
> +}
> +
> +static void hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + memcpy(host->buffer + host->offset, buf, len);
> + host->offset += len;
> +}
> +
> +static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + memcpy(buf, host->buffer + host->offset, len);
> + host->offset += len;
> +}
> +
> +static void set_addr(struct mtd_info *mtd, int column, int page_addr)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> +
> + host->addr_cycle = 0;
> + host->addr_value[0] = 0;
> + host->addr_value[1] = 0;
> +
> + /* Serially input address */
> + if (column != -1) {
> + /* Adjust columns for 16 bit buswidth */
> + if (chip->options & NAND_BUSWIDTH_16)
> + column >>= 1;
> +
> + host->addr_value[0] = column & 0xffff;
> + host->addr_cycle = 2;
> + }
> + if (page_addr != -1) {
> + host->addr_value[0] |= (page_addr & 0xffff)
> + << (host->addr_cycle * 8);
> + host->addr_cycle += 2;
> + /* One more address cycle for devices > 128MiB */
> + if (chip->chipsize > (128 << 20)) {
> + host->addr_cycle += 1;
> + if (host->command == NAND_CMD_ERASE1)
> + host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
> + else
> + host->addr_value[1] |= ((page_addr >> 16) & 0xff);
> + }
> + }
> +}
> +
> +static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
> + int page_addr)
> +{
> + struct nand_chip *chip = mtd->priv;
> + struct hinfc_host *host = chip->priv;
> + int is_cache_invalid = 1;
> + unsigned int flag = 0;
> + host->command = command;
> +
> + switch (command) {
> + case NAND_CMD_READ0:
> + case NAND_CMD_READOOB:
> + if (command == NAND_CMD_READ0)
> + host->offset = column;
> + else
> + host->offset = column + mtd->writesize;
> +
> + is_cache_invalid = 0;
> + set_addr(mtd, column, page_addr);
> + hisi_nfc_send_cmd_readstart(host);
> + break;
> +
> + case NAND_CMD_SEQIN:
> + host->offset = column;
> +
> + case NAND_CMD_ERASE1:
> + set_addr(mtd, column, page_addr);
> + break;
> +
> + case NAND_CMD_PAGEPROG:
> + hisi_nfc_send_cmd_pageprog(host);
> + break;
> +
> + case NAND_CMD_ERASE2:
> + hisi_nfc_send_cmd_erase(host);
> + break;
> +
> + case NAND_CMD_READID:
> + host->offset = column;
> + memset(chip->IO_ADDR_R, 0, 0x10);
> + hisi_nfc_send_cmd_readid(host);
> + break;
> +
> + case NAND_CMD_STATUS:
> + flag = hinfc_read(host, HINFC504_CON);
> + if (chip->ecc.mode == NAND_ECC_HW)
> + hinfc_write(host,
> + flag && ~(HINFC504_CON_ECCTYPE_MASK <<
> + HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
> +
> + host->offset = 0;
> + memset(chip->IO_ADDR_R, 0, 0x10);
> + hisi_nfc_send_cmd_status(host);
> + hinfc_write(host, flag, HINFC504_CON);
> + break;
> +
> + case NAND_CMD_RESET:
> + hisi_nfc_send_cmd_reset(host, host->chipselect);
> + break;
> +
> + default:
> + dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
> + command, column, page_addr);
> + }
> +
> + if (is_cache_invalid) {
> + host->cache_addr_value[0] = ~0;
> + host->cache_addr_value[1] = ~0;
> + }
> +}
> +
> +static irqreturn_t hinfc_irq_handle(int irq, void *devid)
> +{
> + struct hinfc_host *host = devid;
> + unsigned int flag;
> +
> + flag = hinfc_read(host, HINFC504_INTS);
> + /* store interrupts state */
> + host->irq_status |= flag;
> +
> + if (flag & HINFC504_INTS_DMA) {
> + hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
> + complete(&host->cmd_complete);
> + } else if (flag & HINFC504_INTS_CE) {
> + hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
> + } else if (flag & HINFC504_INTS_UE) {
> + hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
> + }
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
> + struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
> +{
> + struct hinfc_host *host = chip->priv;
> + int max_bitflips = 0, stat = 0;
> +
> + chip->read_buf(mtd, buf, mtd->writesize);
> + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
> +
> + /* errors which can not be corrected by ECC */
> + if (host->irq_status & HINFC504_INTS_UE) {
> + mtd->ecc_stats.failed++;
> + } else if (host->irq_status & HINFC504_INTS_CE) {
> + /* need add other ECC modes! */
> + switch (host->ecc_bits) {
> + case 1:
> + stat = hweight8(hinfc_read(host, HINFC504_ECC_STATUS)>>
> + HINFC504_ECC_1_BIT_SHIFT);
> + break;
> + case 6:
> + stat = hweight16(hinfc_read(host, HINFC504_ECC_STATUS)>>
> + HINFC504_ECC_16_BIT_SHIFT & 0x0fff);
> + }
> + mtd->ecc_stats.corrected += stat;
> + max_bitflips = max_t(unsigned int, max_bitflips, stat);
> + }
> + host->irq_status = 0;
> +
> + return max_bitflips;
> +}
> +
> +static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
> + struct nand_chip *chip, const uint8_t *buf, int oob_required)
> +{
> + chip->write_buf(mtd, buf, mtd->writesize);
> + if (oob_required)
> + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
> +
> + return 0;
> +}
> +
> +static void hisi_nfc_host_init(struct hinfc_host *host)
> +{
> + struct nand_chip *chip = &host->chip;
> + host->version = hinfc_read(host, HINFC_VERSION);
> + unsigned int flag = 0;
> +
> + host->addr_cycle = 0;
> + host->addr_value[0] = 0;
> + host->addr_value[1] = 0;
> + host->cache_addr_value[0] = ~0;
> + host->cache_addr_value[1] = ~0;
> + host->chipselect = 0;
> +
> + /* default page size: 2K, ecc_none. need modify */
> + flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
> + | ((0x001 & HINFC504_CON_PAGESIZE_MASK)
> + << HINFC504_CON_PAGEISZE_SHIFT)
> + | ((0x0 & HINFC504_CON_ECCTYPE_MASK)
> + << HINFC504_CON_ECCTYPE_SHIFT)
> + | ((chip->options & NAND_BUSWIDTH_16) ?
> + HINFC504_CON_BUS_WIDTH : 0);
> + hinfc_write(host, flag, HINFC504_CON);
> +
> + memset(chip->IO_ADDR_R, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
> +
> + hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
> + HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
> +
> + /* enable dma irq */
> + hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
> +}
> +
> +static struct nand_ecclayout nand_ecc_2K_1bit = {
> + .oobfree = { {24, 40} }
> +};
> +
> +static struct nand_ecclayout nand_ecc_2K_16bits = {
> + .oobavail = 6,
> + .oobfree = { {2, 6} },
> +};
> +
> +static int hisi_nfc_ecc_probe(struct hinfc_host *host)
> +{
> + struct nand_chip *chip = &host->chip;
> + unsigned int flag;
> +
> + chip->ecc.read_page = hisi_nand_read_page_hwecc;
> + chip->ecc.write_page = hisi_nand_write_page_hwecc;
> +
> + switch (host->ecc_bits) {
> + case 1:
> + chip->ecc.layout = &nand_ecc_2K_1bit;
> + chip->ecc.strength = 1;
> + chip->ecc.size = 512;
> + break;
> + case 6:
> + chip->ecc.layout = &nand_ecc_2K_16bits;
> + chip->ecc.strength = 16;
> + chip->ecc.size = 1024;
> + }
> +
> + flag = hinfc_read(host, HINFC504_CON);
> + /* add ecc type configure */
> + flag |= ((host->ecc_bits & HINFC504_CON_ECCTYPE_MASK)
> + << HINFC504_CON_ECCTYPE_SHIFT);
> + hinfc_write(host, flag, HINFC504_CON);
> +
> + /* enable ecc irq */
> + flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
> + hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
> + HINFC504_INTEN);
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_probe(struct platform_device *pdev)
> +{
> + int ret = 0, irq, buswidth, flag, max_chips = HINFC504_MAX_CHIP;
> + struct device *dev = &pdev->dev;
> + struct hinfc_host *host;
> + struct nand_chip *chip;
> + struct mtd_info *mtd;
> + struct resource *res;
> + struct device_node *np = dev->of_node;
> + struct mtd_part_parser_data ppdata;
> +
> + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
> + if (!host)
> + return -ENOMEM;
> + host->dev = dev;
> +
> + platform_set_drvdata(pdev, host);
> + chip = &host->chip;
> + mtd = &host->mtd;
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(dev, "no IRQ resource defined\n");
> + ret = -ENXIO;
> + goto err_res;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + host->iobase = devm_ioremap_resource(dev, res);
> + if (IS_ERR(host->iobase)) {
> + ret = PTR_ERR(host->iobase);
> + dev_err(dev, "devm_ioremap_resource[0] fail\n");
> + goto err_res;
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + chip->IO_ADDR_R = chip->IO_ADDR_W = devm_ioremap_resource(dev, res);
> + if (IS_ERR(chip->IO_ADDR_R)) {
> + ret = PTR_ERR(chip->IO_ADDR_R);
> + dev_err(dev, "devm_ioremap_resource[1] fail\n");
> + goto err_res;
> + }
> +
> + mtd->priv = chip;
> + mtd->owner = THIS_MODULE;
> + mtd->name = "hisi_nand";
> +
> + chip->priv = host;
> + chip->cmdfunc = hisi_nfc_cmdfunc;
> + chip->select_chip = hisi_nfc_select_chip;
> + chip->read_byte = hisi_nfc_read_byte;
> + chip->read_word = hisi_nfc_read_word;
> + chip->write_buf = hisi_nfc_write_buf;
> + chip->read_buf = hisi_nfc_read_buf;
> + chip->chip_delay = HINFC504_CHIP_DELAY;
> +
> + chip->ecc.mode = of_get_nand_ecc_mode(np);
> + /* read ecc-bits from dts */
> + of_property_read_u32(np, "hisi,nand-ecc-bits", &host->ecc_bits);
> +
> + buswidth = of_get_nand_bus_width(np);
> + if (buswidth == 16)
> + chip->options |= NAND_BUSWIDTH_16;
> +
> + hisi_nfc_host_init(host);
> +
> + ret = devm_request_irq(dev, irq, hinfc_irq_handle, IRQF_DISABLED,
> + "nandc", host);
> + if (ret) {
> + dev_err(dev, "failed to request IRQ\n");
> + goto err_irq;
> + }
> +
> + ret = nand_scan_ident(mtd, max_chips, NULL);
> + if (ret) {
> + ret = -ENODEV;
> + goto err_ident;
> + }
> +
> + host->buffer = dma_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
> + &host->dma_buffer, GFP_KERNEL);
> + if (!host->buffer) {
> + dev_err(dev, "Can't malloc memory for NAND driver.\n");
> + ret = -ENOMEM;
> + goto err_buf;
> + }
> + host->dma_oob = host->dma_buffer + mtd->writesize;
> + memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
> +
> + flag = hinfc_read(host, HINFC504_CON);
> + flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
> + switch (mtd->writesize) {
> + case 2048:
> + flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT);
> + /* add more pagesize support
> + * default pagesize has been set in hisi_nfc_host_init
> + */
> + }
> + hinfc_write(host, flag, HINFC504_CON);
> +
> + if (chip->ecc.mode == NAND_ECC_HW)
> + hisi_nfc_ecc_probe(host);
> +
> + nand_scan_tail(mtd);
> +
> + ppdata.of_node = np;
> + ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
> + if (ret) {
> + dev_err(dev, "Err MTD partition=%d\n", ret);
> + goto err_mtd;
> + }
> +
> + return 0;
> +
> +err_mtd:
> + nand_release(mtd);
> +err_ident:
> +err_irq:
> +err_buf:
> + if (host->buffer)
> + dma_free_coherent(dev, mtd->writesize + mtd->oobsize,
> + host->buffer, host->dma_buffer);
> +err_res:
> + return ret;
> +}
> +
> +static int hisi_nfc_remove(struct platform_device *pdev)
> +{
> + struct hinfc_host *host = platform_get_drvdata(pdev);
> + struct mtd_info *mtd = &host->mtd;
> +
> + nand_release(mtd);
> + dma_free_coherent(&pdev->dev, mtd->writesize + mtd->oobsize,
> + host->buffer, host->dma_buffer);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int hisi_nfc_suspend(struct platform_device *pdev,
> + pm_message_t state)
> +{
> + struct hinfc_host *host = platform_get_drvdata(pdev);
> +
> + while ((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0)
> + ;
> +
> + while ((hinfc_read(host, HINFC504_DMA_CTRL))
> + & HINFC504_DMA_CTRL_DMA_START)
> + _cond_resched();
> +
> + return 0;
> +}
> +
> +static int hisi_nfc_resume(struct platform_device *pdev)
> +{
> + int cs;
> + struct hinfc_host *host = platform_get_drvdata(pdev);
> + struct nand_chip *chip = &host->chip;
> +
> + for (cs = 0; cs < chip->numchips; cs++)
> + hisi_nfc_send_cmd_reset(host, cs);
> + hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
> + HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
> +
> + return 0;
> +}
> +#endif
> +static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
> +
> +static const struct of_device_id nfc_id_table[] = {
> + { .compatible = "hisilicon,504-nfc" },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, nfc_id_table);
> +
> +static struct platform_driver hisi_nfc_driver = {
> + .driver = {
> + .name = "hisi_nand",
> + .of_match_table = of_match_ptr(nfc_id_table),
> + .pm = &hisi_nfc_pm_ops,
> + },
> + .probe = hisi_nfc_probe,
> + .remove = hisi_nfc_remove,
> +};
> +
> +module_platform_driver(hisi_nfc_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Zhiyong Cai");
> +MODULE_AUTHOR("Zhou Wang");
> +MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
>
^ permalink raw reply
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Viresh Kumar @ 2014-07-23 6:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140723065412.GA15759@ulmo.nvidia.com>
On 23 July 2014 12:24, Thierry Reding <thierry.reding@gmail.com> wrote:
> On Wed, Jul 23, 2014 at 10:14:44AM +0530, Viresh Kumar wrote:
>> On 21 July 2014 21:09, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
>>
>> > diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
>> > index 7364a53..df3c73e 100644
>> > --- a/drivers/cpufreq/Kconfig.arm
>> > +++ b/drivers/cpufreq/Kconfig.arm
>> > @@ -244,6 +244,7 @@ config ARM_SPEAR_CPUFREQ
>> > config ARM_TEGRA_CPUFREQ
>> > bool "TEGRA CPUFreq support"
>> > depends on ARCH_TEGRA
>> > + depends on GENERIC_CPUFREQ_CPU0
>>
>> Wouldn't this also disturb the existing cpufreq driver for earlier
>> tegra platforms? i.e. we don't need cpufreq-cpu0 for them
>> atleast as of now.
>
> Perhaps this should be "select" rather than "depends on"?
Don't know, its not optionaly for tegra124 and so a "depends on"
might fit better ?
>> > +static int tegra124_cpufreq_probe(struct platform_device *pdev)
>> > +{
>> > + int ret;
>> > +
>> > + cpu_dev = get_cpu_device(0);
>> > + if (!cpu_dev)
>> > + return -ENODEV;
>> > +
>>
>> Shouldn't we do a of_node_get() here?
>
> I think this would need to be get_device() since it's the struct device
> that's being used subsequently.
Probably I didn't write it well..
What I meant was after doing a get_cpu_device() we might also need
to do of_node_get(cpu_dev->of_node) as we would be using of_node
in further code.
^ permalink raw reply
* [PATCH v1 3/3] mtd: hisilicon: add device tree binding documentation
From: Zhou Wang @ 2014-07-23 7:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405421906-660-4-git-send-email-wangzhou.bry@gmail.com>
On 2014?07?15? 18:58, Zhou Wang wrote:
> Signed-off-by: Zhou Wang <wangzhou.bry@gmail.com>
> ---
> .../devicetree/bindings/mtd/hisi-nand.txt | 40 ++++++++++++++++++++
> 1 file changed, 40 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/hisi-nand.txt
>
Hi Randy Dunlap,
Is there anything that should be modified about this binding document?
It would be very appreciated that I could get some comments from you.
Best regards,
Zhou
> diff --git a/Documentation/devicetree/bindings/mtd/hisi-nand.txt b/Documentation/devicetree/bindings/mtd/hisi-nand.txt
> new file mode 100644
> index 0000000..c8b3988
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mtd/hisi-nand.txt
> @@ -0,0 +1,40 @@
> +Hisilicon Hip04 Soc NAND controller DT binding
> +
> +Required properties:
> +- compatible: Should be "hisilicon,504-nfc".
> +- reg: The first contains base physical address and size of
> + NAND controller's registers. The second contains base
> + physical address and size of NAND controller's buffer.
> +- interrupts: Interrupt number for nfc.
> +- nand-bus-width: See nand.txt.
> +- nand-ecc-mode: See nand.txt.
> +- hisi,nand-ecc-bits: ECC bits type support.
> + <0>: none ecc
> + <1>: Can correct 1bit per 512byte.
> + <6>: Can correct 16bits per 1K byte.
> +- #address-cells: partition address, should be set 1.
> +- #size-cells: partition size, should be set 1.
> +
> +Flash chip may optionally contain additional sub-nodes describing partitions of
> +the address space. See partition.txt for more detail.
> +
> +Example:
> +
> + nand: nand at 4020000 {
> + compatible = "hisilicon,504-nfc";
> + reg = <0x4020000 0x10000>, <0x5000000 0x1000>;
> + interrupts = <0 379 4>;
> + nand-bus-width = <8>;
> + nand-ecc-mode = "hw";
> + hisi,nand-ecc-bits = <1>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + partition at 0 {
> + label = "nand_text";
> + reg = <0x00000000 0x00400000>;
> + };
> +
> + ...
> +
> + };
>
^ permalink raw reply
* [PATCH v5 1/3] arm64: ptrace: reload a syscall number after ptrace operations
From: AKASHI Takahiro @ 2014-07-23 7:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGXu5jKkJUGn_MpEEr8U=n_A+iW9s8vSX1WoVNzRJMVyGQRjpA@mail.gmail.com>
On 07/23/2014 05:15 AM, Kees Cook wrote:
> On Tue, Jul 22, 2014 at 2:14 AM, AKASHI Takahiro
> <takahiro.akashi@linaro.org> wrote:
>> Arm64 holds a syscall number in w8(x8) register. Ptrace tracer may change
>> its value either to:
>> * any valid syscall number to alter a system call, or
>> * -1 to skip a system call
>>
>> This patch implements this behavior by reloading that value into syscallno
>> in struct pt_regs after tracehook_report_syscall_entry() or
>> secure_computing(). In case of '-1', a return value of system call can also
>> be changed by the tracer setting the value to x0 register, and so
>> sys_ni_nosyscall() should not be called.
>>
>> See also:
>> 42309ab4, ARM: 8087/1: ptrace: reload syscall number after
>> secure_computing() check
>>
>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>> ---
>> arch/arm64/kernel/entry.S | 2 ++
>> arch/arm64/kernel/ptrace.c | 13 +++++++++++++
>> 2 files changed, 15 insertions(+)
>>
>> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
>> index 5141e79..de8bdbc 100644
>> --- a/arch/arm64/kernel/entry.S
>> +++ b/arch/arm64/kernel/entry.S
>> @@ -628,6 +628,8 @@ ENDPROC(el0_svc)
>> __sys_trace:
>> mov x0, sp
>> bl syscall_trace_enter
>> + cmp w0, #-1 // skip syscall?
>> + b.eq ret_to_user
>> adr lr, __sys_trace_return // return address
>> uxtw scno, w0 // syscall number (possibly new)
>> mov x1, sp // pointer to regs
>> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
>> index 70526cf..100d7d1 100644
>> --- a/arch/arm64/kernel/ptrace.c
>> +++ b/arch/arm64/kernel/ptrace.c
>> @@ -21,6 +21,7 @@
>>
>> #include <linux/audit.h>
>> #include <linux/compat.h>
>> +#include <linux/errno.h>
>> #include <linux/kernel.h>
>> #include <linux/sched.h>
>> #include <linux/mm.h>
>> @@ -1109,9 +1110,21 @@ static void tracehook_report_syscall(struct pt_regs *regs,
>>
>> asmlinkage int syscall_trace_enter(struct pt_regs *regs)
>> {
>> + unsigned long saved_x0, saved_x8;
>> +
>> + saved_x0 = regs->regs[0];
>> + saved_x8 = regs->regs[8];
>> +
>> if (test_thread_flag(TIF_SYSCALL_TRACE))
>> tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
>>
>> + regs->syscallno = regs->regs[8];
>> + if ((long)regs->syscallno == ~0UL) { /* skip this syscall */
>> + regs->regs[8] = saved_x8;
>> + if (regs->regs[0] == saved_x0) /* not changed by user */
>> + regs->regs[0] = -ENOSYS;
>
> I'm not sure this is right compared to other architectures. Generally
> when a tracer performs a syscall skip, it's up to them to also adjust
> the return value. They may want to be faking a syscall, and what if
> the value they want to return happens to be what x0 was going into the
> tracer? It would have no way to avoid this -ENOSYS case. I think
> things are fine without this test.
Yeah, I know this issue, but was not sure that setting a return value
is mandatory. (x86 seems to return -ENOSYS by default if not explicitly
specified.)
Is "fake a system call" a more appropriate word than "skip"?
I will defer to Will.
Thanks,
-Takahiro AKASHI
> -Kees
>
>> + }
>> +
>> if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
>> trace_sys_enter(regs, regs->syscallno);
>>
>> --
>> 1.7.9.5
>>
>
>
>
^ permalink raw reply
* [PATCH v5 0/3] arm64: Add seccomp support
From: AKASHI Takahiro @ 2014-07-23 7:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGXu5j+1huPbBKH25HK6PmAL3Mi-zgD5UDRp-6wx8vuPVOBDEg@mail.gmail.com>
On 07/23/2014 05:16 AM, Kees Cook wrote:
> On Tue, Jul 22, 2014 at 2:14 AM, AKASHI Takahiro
> <takahiro.akashi@linaro.org> wrote:
>> (Please apply this patch after my audit patch in order to avoid some
>> conflict on arm64/Kconfig.)
>>
>> This patch enables secure computing (system call filtering) on arm64.
>> System calls can be allowed or denied by loaded bpf-style rules.
>> Architecture specific part is to run secure_computing() on syscall entry
>> and check the result. See [3/3]
>
> Thanks for working on this!
>
>> Prerequisites are:
>> * "arm64: Add audit support" patch
>>
>> This code is tested on ARMv8 fast model using
>> * libseccomp v2.1.1 with modifications for arm64 and verified by its "live"
>> tests, 20, 21 and 24.
>> * modified version of Kees' seccomp test for 'changing/skipping a syscall'
>> behavior
>
> Would you be able to share this? I'd love to add it to the seccomp
> regression suite for the arm64-specific parts.
Yep, I forked your repo here:
https://github.com/t-akashi/seccomp.git
(See trace_arm64 branch)
Thanks,
-Takahiro AKASHI
> Thanks!
>
> -Kees
>
>>
>> Changes v4 -> v5:
>> * rebased to v3.16-rc
>> * add patch [1/3] to allow ptrace to change a system call
>> (please note that this patch should be applied even without seccomp.)
>>
>> Changes v3 -> v4:
>> * removed the following patch and moved it to "arm64: prerequisites for
>> audit and ftrace" patchset since it is required for audit and ftrace in
>> case of !COMPAT, too.
>> "arm64: is_compat_task is defined both in asm/compat.h and linux/compat.h"
>>
>> Changes v2 -> v3:
>> * removed unnecessary 'type cast' operations [2/3]
>> * check for a return value (-1) of secure_computing() explicitly [2/3]
>> * aligned with the patch, "arm64: split syscall_trace() into separate
>> functions for enter/exit" [2/3]
>> * changed default of CONFIG_SECCOMP to n [2/3]
>>
>> Changes v1 -> v2:
>> * added generic seccomp.h for arm64 to utilize it [1,2/3]
>> * changed syscall_trace() to return more meaningful value (-EPERM)
>> on seccomp failure case [2/3]
>> * aligned with the change in "arm64: make a single hook to syscall_trace()
>> for all syscall features" v2 [2/3]
>> * removed is_compat_task() definition from compat.h [3/3]
>>
>> AKASHI Takahiro (3):
>> arm64: ptrace: reload a syscall number after ptrace operations
>> asm-generic: Add generic seccomp.h for secure computing mode 1
>> arm64: Add seccomp support
>>
>> arch/arm64/Kconfig | 14 ++++++++++++++
>> arch/arm64/include/asm/seccomp.h | 25 +++++++++++++++++++++++++
>> arch/arm64/include/asm/unistd.h | 3 +++
>> arch/arm64/kernel/entry.S | 2 ++
>> arch/arm64/kernel/ptrace.c | 18 ++++++++++++++++++
>> include/asm-generic/seccomp.h | 28 ++++++++++++++++++++++++++++
>> 6 files changed, 90 insertions(+)
>> create mode 100644 arch/arm64/include/asm/seccomp.h
>> create mode 100644 include/asm-generic/seccomp.h
>>
>> --
>> 1.7.9.5
>>
>
>
>
^ permalink raw reply
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Thierry Reding @ 2014-07-23 7:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405957142-19416-15-git-send-email-ttynkkynen@nvidia.com>
On Mon, Jul 21, 2014 at 06:39:00PM +0300, Tuomas Tynkkynen wrote:
[...]
> diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c
[...]
> +static int tegra124_cpu_switch_to_dfll(void)
> +{
> + struct clk *original_cpu_clk_parent;
Maybe just "parent"?
> + unsigned long rate;
> + struct dev_pm_opp *opp;
> + int ret;
> +
> + rate = clk_get_rate(cpu_clk);
> + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
> + if (IS_ERR(opp))
> + return PTR_ERR(opp);
> +
> + ret = clk_set_rate(dfll_clk, rate);
> + if (ret)
> + return ret;
> +
> + original_cpu_clk_parent = clk_get_parent(cpu_clk);
> + clk_set_parent(cpu_clk, pllp_clk);
> + if (ret)
> + return ret;
> +
> + ret = clk_prepare_enable(dfll_clk);
> + if (ret)
> + goto out_switch_to_original_parent;
This could simply be "out" or "err" or anything else shorter than the
above.
> +
> + clk_set_parent(cpu_clk, dfll_clk);
> +
> + return 0;
> +
> +out_switch_to_original_parent:
> + clk_set_parent(cpu_clk, original_cpu_clk_parent);
> +
> + return ret;
> +}
> +
> +static struct platform_device_info cpufreq_cpu0_devinfo = {
> + .name = "cpufreq-cpu0",
> +};
> +
> +static int tegra124_cpufreq_probe(struct platform_device *pdev)
> +{
> + int ret;
> +
> + cpu_dev = get_cpu_device(0);
> + if (!cpu_dev)
> + return -ENODEV;
> +
> + cpu_clk = of_clk_get_by_name(cpu_dev->of_node, "cpu_g");
> + if (IS_ERR(cpu_clk))
> + return PTR_ERR(cpu_clk);
> +
> + dfll_clk = of_clk_get_by_name(cpu_dev->of_node, "dfll");
> + if (IS_ERR(dfll_clk)) {
> + ret = PTR_ERR(dfll_clk);
> + goto out_put_cpu_clk;
> + }
> +
> + pllx_clk = of_clk_get_by_name(cpu_dev->of_node, "pll_x");
> + if (IS_ERR(pllx_clk)) {
> + ret = PTR_ERR(pllx_clk);
> + goto out_put_dfll_clk;
> + }
> +
> + pllp_clk = of_clk_get_by_name(cpu_dev->of_node, "pll_p");
> + if (IS_ERR(pllp_clk)) {
> + ret = PTR_ERR(pllp_clk);
> + goto out_put_pllx_clk;
> + }
Can the above not be devm_clk_get(cpu_dev, "...") so that you can remove
all the clk_put() calls in the cleanup code below?
> +
> + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
> + if (ret)
> + goto out_put_pllp_clk;
> +
> + ret = tegra124_cpu_switch_to_dfll();
> + if (ret)
> + goto out_free_table;
> +
> + platform_device_register_full(&cpufreq_cpu0_devinfo);
Should the cpufreq_cpu0_devinfo device perhaps be a child of pdev?
> +
> + return 0;
> +
> +out_free_table:
> + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
> +out_put_pllp_clk:
> + clk_put(pllp_clk);
> +out_put_pllx_clk:
> + clk_put(pllx_clk);
> +out_put_dfll_clk:
> + clk_put(dfll_clk);
> +out_put_cpu_clk:
> + clk_put(cpu_clk);
> +
> + return ret;
> +}
> +
> +static struct platform_driver tegra124_cpufreq_platdrv = {
> + .driver = {
> + .name = "cpufreq-tegra124",
> + .owner = THIS_MODULE,
> + },
> + .probe = tegra124_cpufreq_probe,
Note that simply leaving out .remove() here doesn't guarantee that the
driver won't be unloaded. Also building it into the kernel doesn't
prevent that. You can still unbind the driver via sysfs. So you'd need
to add a .suppress_bind_attrs = true above.
But is there even a reason why we need that? Couldn't we make the
driver's .remove() undo what .probe() did so that the driver can be
unloaded?
Otherwise it probably makes more sense not to use a driver (and dummy
device) at all as Viresh already mentioned.
> +};
> +
> +static const struct of_device_id soc_of_matches[] = {
> + { .compatible = "nvidia,tegra124", },
> + {}
> +};
> +
> +static int __init tegra_cpufreq_init(void)
> +{
> + int ret;
> + struct platform_device *pdev;
> +
> + if (!of_find_matching_node(NULL, soc_of_matches))
> + return -ENODEV;
I think this could be of_machine_is_compatible() since there's only a
single entry in the match table. If there's a good chance that we may
end up with more entries, perhaps now would be a good time to add an
of_match_machine() function?
> +
> + ret = platform_driver_register(&tegra124_cpufreq_platdrv);
> + if (ret)
> + return ret;
> +
> + pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0);
> + if (IS_ERR(pdev)) {
> + platform_driver_unregister(&tegra124_cpufreq_platdrv);
> + return PTR_ERR(pdev);
> + }
> +
> + return 0;
> +}
> +
> +MODULE_AUTHOR("Tuomas Tynkkynen <ttynkkynen@nvidia.com>");
> +MODULE_DESCRIPTION("cpufreq driver for nVIDIA Tegra124");
We use "NVIDIA" everywhere nowadays.
> +MODULE_LICENSE("GPLv2");
The correct license string is "GPL v2".
> +module_init(tegra_cpufreq_init);
The placement of this is unusual. It should go immediately below the
tegra_cpufreq_init() function.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140723/1a280ee0/attachment-0001.sig>
^ permalink raw reply
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: pramod gurav @ 2014-07-23 7:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405957142-19416-15-git-send-email-ttynkkynen@nvidia.com>
On Mon, Jul 21, 2014 at 9:09 PM, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
> Add a new cpufreq driver for Tegra124. Instead of using the PLLX as
<snip>
> +
> +static int tegra124_cpu_switch_to_dfll(void)
> +{
> + struct clk *original_cpu_clk_parent;
> + unsigned long rate;
> + struct dev_pm_opp *opp;
> + int ret;
> +
> + rate = clk_get_rate(cpu_clk);
> + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
> + if (IS_ERR(opp))
> + return PTR_ERR(opp);
> +
> + ret = clk_set_rate(dfll_clk, rate);
> + if (ret)
> + return ret;
> +
> + original_cpu_clk_parent = clk_get_parent(cpu_clk);
> + clk_set_parent(cpu_clk, pllp_clk);
Needs return check.
> + if (ret)
> + return ret;
Which 'ret' is being checked here? nothing is assigned here. May be
fixing previous comment will fix this.
> +
> + ret = clk_prepare_enable(dfll_clk);
<snip>
> Please read the FAQ at http://www.tux.org/lkml/
--
Thanks and Regards
Pramod
^ permalink raw reply
* [PATCH v2 14/16] cpufreq: Add cpufreq driver for Tegra124
From: Thierry Reding @ 2014-07-23 7:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohponmg24pvnX2Jhfg5LHKKHx3VEm-6a_JXTGhVXY-aj3EOw@mail.gmail.com>
On Wed, Jul 23, 2014 at 12:28:21PM +0530, Viresh Kumar wrote:
> On 23 July 2014 12:24, Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Wed, Jul 23, 2014 at 10:14:44AM +0530, Viresh Kumar wrote:
> >> On 21 July 2014 21:09, Tuomas Tynkkynen <ttynkkynen@nvidia.com> wrote:
> >>
> >> > diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
> >> > index 7364a53..df3c73e 100644
> >> > --- a/drivers/cpufreq/Kconfig.arm
> >> > +++ b/drivers/cpufreq/Kconfig.arm
> >> > @@ -244,6 +244,7 @@ config ARM_SPEAR_CPUFREQ
> >> > config ARM_TEGRA_CPUFREQ
> >> > bool "TEGRA CPUFreq support"
> >> > depends on ARCH_TEGRA
> >> > + depends on GENERIC_CPUFREQ_CPU0
> >>
> >> Wouldn't this also disturb the existing cpufreq driver for earlier
> >> tegra platforms? i.e. we don't need cpufreq-cpu0 for them
> >> atleast as of now.
> >
> > Perhaps this should be "select" rather than "depends on"?
>
> Don't know, its not optionaly for tegra124 and so a "depends on"
> might fit better ?
ARM_TEGRA_CPUFREQ is still optional, so the select only applies when the
Tegra cpufreq driver is enabled. This is mostly just out of convenience,
though. The Tegra cpufreq driver uses the generic CPU0 cpufreq driver so
a select will automatically pull in the necessary dependency. With a
"depends on" the Tegra cpufreq driver only becomes available after
you've selected GENERIC_CPUFREQ_CPU0, which is somewhat unintuitive.
To illustrate with an example: as a user, I want to enable CPU frequency
scaling on Tegra. So I use menuconfig to navigate to the "CPU Frequency
scaling" menu (enable it if not available yet) and look for an entry
that says "Tegra". But I can't find it because it's hidden due to the
lack of GENERIC_CPUFREQ_CPU0. That the Tegra CPU frequency driver uses a
generic driver is an implementation detail that users shouldn't have to
be aware of.
> >> > +static int tegra124_cpufreq_probe(struct platform_device *pdev)
> >> > +{
> >> > + int ret;
> >> > +
> >> > + cpu_dev = get_cpu_device(0);
> >> > + if (!cpu_dev)
> >> > + return -ENODEV;
> >> > +
> >>
> >> Shouldn't we do a of_node_get() here?
> >
> > I think this would need to be get_device() since it's the struct device
> > that's being used subsequently.
>
> Probably I didn't write it well..
>
> What I meant was after doing a get_cpu_device() we might also need
> to do of_node_get(cpu_dev->of_node) as we would be using of_node
> in further code.
But we're using cpu_dev->of_node, so we need to make sure cpu_dev
doesn't go away suddenly. Simply keeping a reference to ->of_node
won't ensure that.
I guess technically it would be better if get_cpu_device() already
incremented the reference count on the returned struct device. Currently
it would theoretically still be possible for the device to disappear
between the call to get_cpu_device() and a call to get_device().
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140723/8de8a192/attachment.sig>
^ permalink raw reply
* [PATCH v2] cpufreq: tests: Providing cpufreq regression test
From: Lukasz Majewski @ 2014-07-23 7:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKohpondk7Cty8MhTcjyzZW8Z0o4AVupYE0rRnG4YJf+SmDyjg@mail.gmail.com>
Hi Viresh,
> Hi Lukasz,
>
> I haven't replied yet as I wanted to see what the general feed of
> Rafael is going to be :)
>
> As this is something new and wasn't sure if we really want this..
Do you want to say that we have enough tests and we don't need more ?
I always thought that we shall have as much regression tests as
possible.
>
> On 21 July 2014 12:32, Lukasz Majewski <l.majewski@samsung.com> wrote:
> > This commit adds first regression test "cpufreq_freq_test.sh" for
> > the cpufreq subsystem.
>
> That's not enough, Tell us why we should continue reading this mail..
Hmm... If "regression" and "test" don't catch the attention of a
diligent maintainer, then I cannot do much more to encourage him to
read the whole e-mail :-)
I can imagine that maintainers are very busy, therefore I've prepared
README file with detailed description of the script operation.
>
> > Signed-off-by: Lukasz Majewski <l.majewski@samsung.com>
> >
> > ---
> > Changes for v2:
> > - Replace *_PATCH with *_PATH for variables names
> > - Corrected mistakes in the README file
> > - Providing detailed explanation of the patch in the README file
> > ---
> > drivers/cpufreq/tests/README | 33 +++++++
> > drivers/cpufreq/tests/cpufreq_freq_test.sh | 149
> > +++++++++++++++++++++++++++++
>
> Probably a better place would be tools/power/cpufreq/
>
> @Rafael?
Rafael, I'm open for suggestions.
>
> > 2 files changed, 182 insertions(+)
> > create mode 100644 drivers/cpufreq/tests/README
> > create mode 100755 drivers/cpufreq/tests/cpufreq_freq_test.sh
> >
> > diff --git a/drivers/cpufreq/tests/README
> > b/drivers/cpufreq/tests/README new file mode 100644
> > index 0000000..3e9cd80
> > --- /dev/null
> > +++ b/drivers/cpufreq/tests/README
> > @@ -0,0 +1,33 @@
> > +This file contains list of cpufreq's available regression tests
> > with a short +usage description.
> > +
> > +1. cpufreq_freq_test.sh
> > +
> > +Description:
> > +------------
> > +This script is supposed to test if cpufreq attributes exported by
> > sysfs are +exposing correct values.
> > +
> > +To achieve this goal it saves the current governor and changes it
> > to +"performance". Afterwards, it reads the
> > "scaling_available_frequencies" +property. With the list of
> > supported frequencies it is able to enforce each of +them by
> > writing to "scaling_max_freq" attribute. To make the test more
> > reliable +a superfluous load with gzip is created to be sure that
> > we are running with +highest possible frequency. This high load is
> > regulated with the 'sleep' +duration. After this time the
> > "cpufreq_cur_freq" is read and compared with the +original value.
> > As the last step the original governor is restored.
>
> I couldn't make out the purpose of this test and why we need it. How
> do we ensure that "cpufreq attributes exported by sysfs are exposing
> correct values"?
First of all the cpufreq attributes are part of the subsystem API.
There are systems which actually depend on them, so we would be better
off to test if they work as intended.
Secondly, the test takes those values and then with use of other
attribute enforce the value, which is then read via cat'ing
cpufreq_cur_freq. If any of the attributes is wrong then we will spot
the error immediately.
>
> And actually what do we mean by this statement even? What kind of
> errors can be there in exposing these values.
Errors with cpufreq and CCF cooperation - especially when some parts of
cpufreq code uses direct write to MUX, DIV or PLL SoC registers.
Also, one can check if permutations of changing all available
frequencies are working properly.
This script allowed me to find at least two bugs at Exynos cpufreq
subsystem in the past. And those fixes are already applied to mainline.
>
> I want to understand the purpose of this script very clearly first
> and then only will look at the details.
There is a clean shell script code to go through it, the README file
with detailed description of the script purpose and operation.
What else shall I write?
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ 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