Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/2] ARM: mm: keep rodata non-executable
From: Dave Martin @ 2014-02-14 16:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392339850-18686-3-git-send-email-keescook@chromium.org>

On Thu, Feb 13, 2014 at 05:04:10PM -0800, Kees Cook wrote:
> Introduce "CONFIG_DEBUG_RODATA" to mostly match the x86 config, though
> the behavior is different: it depends on STRICT_KERNMEM_PERMS, which
> sets rodata read-only (but executable), where as this option additionally
> splits rodata from the kernel text (resulting in potentially more memory
> lost to padding) and sets it non-executable as well. The end result is
> that on builds with CONFIG_DEBUG_RODATA=y (like x86) the rodata with be
> marked purely read-only.

This triggers an Oops in kexec, because we have a block of code in .text
which is a template for generating baremetal code to relocate the new
kernel, and some literal words are written into it before copying.

Possibly this should be in .rodata, not .text.

There may be a few other instances of this kind of thing.

Are you aware of similar situations on other arches?

Cheers
---Dave

^ permalink raw reply

* [BISECTED] ssh - Received disconnect from x.x.x.x: 2: Bad packet length 3149594624
From: Will Deacon @ 2014-02-14 16:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52FE407C.3080002@gmail.com>

On Fri, Feb 14, 2014 at 04:12:44PM +0000, Ivaylo Dimitrov wrote:
> On 13.02.2014 21:29, Will Deacon wrote:
> >
> > Can you try hacking crypto/memneq.c so that it doesn't use
> > CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS please? That would at least point the
> > finger at net/mac80211/rx.c or similar.
> >
> 
> Well, I am lazy so I hacked net/mac80211/rx.c first:

No problem, thanks for having a go.

> index c24ca0d..6839c77 100644
> --- a/net/mac80211/rx.c
> +++ b/net/mac80211/rx.c
> @@ -1963,7 +1963,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
>                  }
>          }
> 
> -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> +//#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
>          if (skb) {
>                  /* 'align' will only take the values 0 or 2 here since all
>                   * frames are required to be aligned to 2-byte boundaries
> @@ -1987,7 +1987,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
>                          }
>                  }
>          }
> -#endif
> +//#endif
> 
>          if (skb) {
>                  /* deliver to local stack */
> 
> 
> and that seems to fix the problem.
> 
> I am not sure whom I should forward the problem.

Well, we probably need a bit more to go on, because I doubt that this code
is to blame. More likely, the issue is in the caller.
Looking at drivers/net/wireless/ti/wl1251/rx.c:182

        /* The actual length doesn't include the target's alignment */
        skb->len = desc->length  - PLCP_HEADER_LENGTH;

        fc = (u16 *)skb->data;

        if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
                beacon = 1;

        wl1251_rx_status(wl, desc, &status, beacon);

        wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
                     beacon ? "beacon" : "");

        memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
        ieee80211_rx_ni(wl->hw, skb);

I wonder whether that first line (with the comment about alignment) is
assuming some behaviour from the mac80211 layer.

You could try putting back the UNALIGNED_ACCESS in net/mac80211/rx.c and
commenting out the skb->len = desc->length  - PLCP_HEADER_LENGTH;  line
above.

Adding the original author (I think) and John Linville, since I'm well out
of my depth in this code!

Will

^ permalink raw reply

* [PATCH 26/27] ARM: shmobile: lager-reference: Enable CMT0 in device tree
From: Laurent Pinchart @ 2014-02-14 16:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52FE29DB.2010304@cogentembedded.com>

Hi Sergei,

On Friday 14 February 2014 18:36:11 Sergei Shtylyov wrote:
> Hello.
> 
> On 14-02-2014 18:22, Laurent Pinchart wrote:
> >>>>> Enable the CMT0 device and configure channel 0 as a clock event
> >>>>> provider.
> >>>>> 
> >>>>> Signed-off-by: Laurent Pinchart
> >>>>> <laurent.pinchart+renesas@ideasonboard.com>
> >>>>> 
> >>>>> diff --git a/arch/arm/mach-shmobile/include/mach/r8a7790.h
> >>>>> b/arch/arm/mach-shmobile/include/mach/r8a7790.h index 0b95bab..62b31f3
> >>>>> 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7790.h
> >>>>> +++ b/arch/arm/mach-shmobile/include/mach/r8a7790.h
> >>>>> @@ -29,7 +29,6 @@ enum {
> >>>>> 
> >>>>>   };
> >>>>>   
> >>>>>   void r8a7790_add_standard_devices(void);
> >>>>> 
> >>>>> -void r8a7790_add_dt_devices(void);
> >>>>> 
> >>>>>   void r8a7790_clock_init(void);
> >>>>>   void r8a7790_pinmux_init(void);
> >>>>>   void r8a7790_pm_init(void);
> >>>>> 
> >>>>> diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c
> >>>>> b/arch/arm/mach-shmobile/setup-r8a7790.c index 3e5813f..462c81f 100644
> >>>>> --- a/arch/arm/mach-shmobile/setup-r8a7790.c
> >>>>> +++ b/arch/arm/mach-shmobile/setup-r8a7790.c
> >>>>> @@ -294,11 +294,6 @@ static struct resource cmt0_resources[] = {
> >>>>>     					  &cmt##idx##_platform_data,	\
> >>>>>     					  sizeof(struct sh_timer_config))
> >>>>> 
> >>>>> -void __init r8a7790_add_dt_devices(void)
> >>>>> -{
> >>>>> -	r8a7790_register_cmt(0);
> >>>>> -}
> >>>>> -
> >>>>>  void __init r8a7790_add_standard_devices(void)
> >>>>>  {
> >>>>>     	r8a7790_register_scif(0);
> >>>>> @@ -311,7 +306,7 @@ void __init r8a7790_add_standard_devices(void)
> >>>>> 	r8a7790_register_scif(7);
> >>>>>  	r8a7790_register_scif(8);
> >>>>>  	r8a7790_register_scif(9);
> >>>>> -	r8a7790_add_dt_devices();
> >>>>> +	r8a7790_register_cmt(0);
> >>>>> 	r8a7790_register_irqc(0);
> >>>>> 	r8a7790_register_thermal();
> >>>>> }
> >>>> 
> >>>> IMHO, these 2 files should be split into a separate patch.
> >>> 
> >>> That could easily be done, but why ?
> >> 
> >> It does not seem necessary to combine these changes in one patch.
> >> Remember, Simon has separate branches for boards and SoCs. So finally
> >> it's up to him to decide on this...
> > 
> > Right, but in this case I need to remove the CMT platform device
> > registration from r8a7790_add_dt_devices()
> 
> You're not removing anything in these 2 files, you're just replacing
> "indirect" call to r8a7790_register_cmt(0) with direct.

OK, I see what you mean now. Given that the patch removes the 
r8a7790_add_dt_devices() call from arch/arm/mach-shmobile/board-lager-
reference.c, I could indeed split those two changes into a separate patch as 
there's no-one calling the function anymore. That would introduce a dependency 
between the branches, which might not be better. I'll let Simon comment on 
what he would prefer and will act accordingly.

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH 3/6] irqchip: gic: use writel instead of dsb + writel_relaxed
From: Will Deacon @ 2014-02-14 16:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140207112337.GC5976@mudshark.cambridge.arm.com>

Well, the results are in (*drum roll*)...

On Fri, Feb 07, 2014 at 11:23:37AM +0000, Will Deacon wrote:
> On Thu, Feb 06, 2014 at 03:20:48PM +0000, Catalin Marinas wrote:
> > On Thu, Feb 06, 2014 at 01:26:44PM +0000, Will Deacon wrote:
> > > Ok, my reasoning is as follows:
> > > 
> > >   - CPU0 tries to message CPU1. It writes to a location in normal memory,
> > >     then writes to the GICD to send the SGI
> > > 
> > >   - We need to ensure that CPU1 observes the write to normal memory before
> > >     the write to GICD reaches the distributor. This is *not* about end-point
> > >     ordering (the usual non-coherent DMA example).
> > > 
> > >   - A dmb ishst ensures that the two writes are observed in order by CPU1
> > >     (and, in fact, the inner-shareable domain containing CPU0).
> > 
> > The last bullet point is not correct. DMB would only guarantee that the
> > two writes (memory and GICD) are observed by CPU1 if CPU1 actually read
> > the GICD (observability is defined for master accesses).
> 
> Rather than attempt to solve this via email (your examples below are already
> getting hard to follow :), how about we sit down with $drink_of_choice and
> post back here with our conclusions?

... and it turns out that a dmb(ishst) is sufficient!

This counter-intuitive result was brought to you by ARM Ltd, purveyors of
fine grained memory barrier instructions.

I'll spin the patch again.

Will

^ permalink raw reply

* [PATCH V2 1/2] mmc: omap_hsmmc: Add support for quirky omap3 hsmmc controller
From: Tony Lindgren @ 2014-02-14 16:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392356749-32091-2-git-send-email-nm@ti.com>

* Nishanth Menon <nm@ti.com> [140213 21:48]:
> When device is booted using devicetree, platforms impacted by Erratum
> 2.1.1.128 is not detected easily in the mmc driver. This erratum
> indicates that the module cannot do multi-block transfers. Platforms
> such as LDP which use OMAP3 ES revision prior to ES3.0 are impacted by
> this.
> 
> Provide a new compatible property "ti,omap3-pre-es3-hsmmc" to allow
> driver to determine if driver needs to implement quirks associated
> with the specific module version (primarily because the IP revision
> information is not sufficient for the same).
> 
> Signed-off-by: Nishanth Menon <nm@ti.com>

Looks good to me, would be good to get this into the -rc cycle
as LDP is one of the automated boot testing boards for us.

If you guys want me to pick up both of the patches let me know,
otherwise feel free to add my ack.

Regards,

Tony

^ permalink raw reply

* [PATCH v2] MAINTAINERS: add additional ARM BCM281xx/BCM11xxx maintainer
From: Christian Daudt @ 2014-02-14 16:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392390903-19826-1-git-send-email-mporter@linaro.org>

On Fri, Feb 14, 2014 at 7:15 AM, Matt Porter <mporter@linaro.org> wrote:
> Add myself as an additional maintainer for the Broadcom mobile
> SoCs.
>
> Signed-off-by: Matt Porter <mporter@linaro.org>
> ---
> Since v1: put back my missing SOB
>
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b2cf5cf..9d6fbfd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1860,6 +1860,7 @@ F:        drivers/net/ethernet/broadcom/bnx2x/
>
>  BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
>  M:     Christian Daudt <bcm@fixthebug.org>
> +M:     Matt Porter <mporter@linaro.org>
>  L:     bcm-kernel-feedback-list at broadcom.com
>  T:     git git://git.github.com/broadcom/bcm11351
>  S:     Maintained
> --
> 1.8.4
>
Acked-by: Christian Daudt <bcm@fixthebug.org>

^ permalink raw reply

* [PATCH v2 4/4] Documentation: dt: OMAP: Update Overo/Tobi
From: Tony Lindgren @ 2014-02-14 16:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <52FDD082.9090006@ti.com>

* Nishanth Menon <nm@ti.com> [140214 00:17]:
> On 02/14/2014 01:58 AM, Florian Vaussard wrote:
> > Hi,
> > 
> > On 02/13/2014 03:43 PM, Nishanth Menon wrote:
> >> On 02/13/2014 04:25 AM, Florian Vaussard wrote:
> >>> Update the compatible string for Overo/Tobi to reflect the latest
> >>> changes.
> >>>
> >>> Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
> >>> ---
> >>>  Documentation/devicetree/bindings/arm/omap/omap.txt | 2 +-
> >>>  1 file changed, 1 insertion(+), 1 deletion(-)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
> >>> index 34dc40c..af9b4a0 100644
> >>> --- a/Documentation/devicetree/bindings/arm/omap/omap.txt
> >>> +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
> >>> @@ -91,7 +91,7 @@ Boards:
> >>>    compatible = "ti,omap3-beagle", "ti,omap3"
> >>>  
> >>>  - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
> >>> -  compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
> >>> +  compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
> >> omap3-overo-storm-tobi.dts is not covered here, so, I wonder as the
> >> number of boards supported keep increasing, is'nt it better we drop
> >> the board information from omap.txt?
> >>
> > 
> > I am not opposed to this. We will just have checkpatch warnings due to
> > undocumented compatible strings.
> 
> Aaah, I seemed to have missed bff5da43 commit, thanks for pointing me
> at it - unrelated to this patch, I think the board cleanups is a
> little overdue :(
> 
> Acked-by: Nishanth Menon <nm@ti.com>

OK thanks picking up this too.

Tony

^ permalink raw reply

* [PATCH 1/2] clk: fixed-rate: use full DT node name
From: Stephen Warren @ 2014-02-14 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140214103556.GC9907@e106331-lin.cambridge.arm.com>

On 02/14/2014 03:35 AM, Mark Rutland wrote:
> On Fri, Feb 14, 2014 at 06:16:52AM +0000, Stephen Warren wrote:
>> clk-fixed-rate currently names clocks according to a node's name without
>> the unit address. When faced with the legal and technically correct DT
>> structure below, this causes rgistration attempts for 3 clocks with the
>> same name, 2 of which fail.
>>
>> 	clocks {
>> 		compatible = "simple-bus";
>> 		#address-cells = <1>;
>> 		#size-cells = <0>;
>>
>> 		clk_mmc: clock at 0 {
>> 			compatible = "fixed-clock";
>> 			reg = <0>;
>> ...
>> 		clk_i2c: clock at 1 {
>> 			compatible = "fixed-clock";
>> 			reg = <1>;
>> ...
>> 		clk_spi: clock at 2 {
>> 			compatible = "fixed-clock";
>> 			reg = <2>;
>> ...
> 
> I'd argue that this case isn't valid.

Well, it's very widely used, and was the result of numerous discussions
of how this kind of thing should be represented:-/

> The fixed-clock binding doesn't define a reg, yet simple bus binding
> implies that the reg property of child nodes should be interpretted as
> the same address space as their parent (MMIO in this case?). The
> fixed-clock nodes reg proeprties clearly aren't MMIO addresses.
> 
> Additionally, the _requred_ ranges property is missing.

Perhaps we need to invent a simple-container instead then?

> It's just nonsensical; rename them to clock_{0,1,..} instead and get rid
> of the reg properties. Then they're named uniquely.

That's not legal either. DT node names are supposed to represent the
type of device/object (i.e. just "clock"), not the identity of the
device/object (i.e. not include IDs etc.). Hence, the node name needs to
be "clock" for all of them, and the unit address must be used to
differentiate them.

^ permalink raw reply

* [PATCH 1/2] clk: fixed-rate: use full DT node name
From: Stephen Warren @ 2014-02-14 16:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140214103556.GC9907@e106331-lin.cambridge.arm.com>

On 02/14/2014 03:35 AM, Mark Rutland wrote:
> On Fri, Feb 14, 2014 at 06:16:52AM +0000, Stephen Warren wrote:
>> clk-fixed-rate currently names clocks according to a node's name without
>> the unit address. When faced with the legal and technically correct DT
>> structure below, this causes rgistration attempts for 3 clocks with the
>> same name, 2 of which fail.
>>
>> 	clocks {
>> 		compatible = "simple-bus";
>> 		#address-cells = <1>;
>> 		#size-cells = <0>;
>>
>> 		clk_mmc: clock at 0 {
>> 			compatible = "fixed-clock";
>> 			reg = <0>;
>> ...
>> 		clk_i2c: clock at 1 {
>> 			compatible = "fixed-clock";
>> 			reg = <1>;
>> ...
>> 		clk_spi: clock at 2 {
>> 			compatible = "fixed-clock";
>> 			reg = <2>;
>> ...
> 
> I'd argue that this case isn't valid.
> 
> The fixed-clock binding doesn't define a reg, yet simple bus binding
> implies that the reg property of child nodes should be interpretted as
> the same address space as their parent (MMIO in this case?). The
> fixed-clock nodes reg proeprties clearly aren't MMIO addresses.
> 
> Additionally, the _requred_ ranges property is missing.

Oh, IIRC that was deliberate to indicate that the child address space
was disjoint from the parent address space.

^ permalink raw reply

* [PATCH 3/6] irqchip: gic: use writel instead of dsb + writel_relaxed
From: Catalin Marinas @ 2014-02-14 16:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140214163039.GG21986@mudshark.cambridge.arm.com>

On Fri, Feb 14, 2014 at 04:30:39PM +0000, Will Deacon wrote:
> Well, the results are in (*drum roll*)...
> 
> On Fri, Feb 07, 2014 at 11:23:37AM +0000, Will Deacon wrote:
> > On Thu, Feb 06, 2014 at 03:20:48PM +0000, Catalin Marinas wrote:
> > > On Thu, Feb 06, 2014 at 01:26:44PM +0000, Will Deacon wrote:
> > > > Ok, my reasoning is as follows:
> > > > 
> > > >   - CPU0 tries to message CPU1. It writes to a location in normal memory,
> > > >     then writes to the GICD to send the SGI
> > > > 
> > > >   - We need to ensure that CPU1 observes the write to normal memory before
> > > >     the write to GICD reaches the distributor. This is *not* about end-point
> > > >     ordering (the usual non-coherent DMA example).
> > > > 
> > > >   - A dmb ishst ensures that the two writes are observed in order by CPU1
> > > >     (and, in fact, the inner-shareable domain containing CPU0).
> > > 
> > > The last bullet point is not correct. DMB would only guarantee that the
> > > two writes (memory and GICD) are observed by CPU1 if CPU1 actually read
> > > the GICD (observability is defined for master accesses).
> > 
> > Rather than attempt to solve this via email (your examples below are already
> > getting hard to follow :), how about we sit down with $drink_of_choice and
> > post back here with our conclusions?
> 
> ... and it turns out that a dmb(ishst) is sufficient!

Until we hear otherwise ;)

-- 
Catalin

^ permalink raw reply

* [PATCH v2 0/2] Introduce omap-des driver for OMAP SoCs
From: Joel Fernandes @ 2014-02-14 16:48 UTC (permalink / raw)
  To: linux-arm-kernel

Here are revised patches for omap-des driver addressing review comments at:
https://lkml.org/lkml/2013/8/30/116

Joel Fernandes (2):
  crypto: omap-des: Add omap-des driver for OMAP4/AM43xx
  crypto: omap-des: Add config and build options

 drivers/crypto/Kconfig    |   11 +
 drivers/crypto/Makefile   |    1 +
 drivers/crypto/omap-des.c | 1218 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1230 insertions(+)
 create mode 100644 drivers/crypto/omap-des.c

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v2 1/2] crypto: omap-des: Add omap-des driver for OMAP4/AM43xx
From: Joel Fernandes @ 2014-02-14 16:49 UTC (permalink / raw)
  To: linux-arm-kernel

Add omap-des driver with platform data for OMAP4/AM43xx. Support added for DES
ECB and CBC modes. Also add support for 3DES operation where 3 64-bit keys are
used to perform a DES encrypt-decrypt-encrypt (des3_ede) operation on a buffer.

Tests have been conducted with the CRYPTO test manager, and functionality is
verified at different page length alignments.

Signed-off-by: Joel Fernandes <joelf@ti.com>
---
v2 changes:
Address review comments from Rajendra at: https://lkml.org/lkml/2013/8/30/116

 drivers/crypto/omap-des.c | 1218 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1218 insertions(+)
 create mode 100644 drivers/crypto/omap-des.c

diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
new file mode 100644
index 0000000..006d914
--- /dev/null
+++ b/drivers/crypto/omap-des.c
@@ -0,0 +1,1218 @@
+/*
+ * Support for OMAP DES and Triple DES HW acceleration.
+ *
+ * Copyright (c) 2013 Texas Instruments Incorporated
+ * Author: Joel Fernandes <joelf@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#ifdef DEBUG
+#define prn(num) printk(#num "=%d\n", num)
+#define prx(num) printk(#num "=%x\n", num)
+#else
+#define prn(num) do { } while (0)
+#define prx(num)  do { } while (0)
+#endif
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/des.h>
+
+#define DST_MAXBURST			2
+
+#define DES_BLOCK_WORDS		(DES_BLOCK_SIZE >> 2)
+
+#define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
+
+#define DES_REG_KEY(dd, x)		((dd)->pdata->key_ofs - \
+						((x ^ 0x01) * 0x04))
+
+#define DES_REG_IV(dd, x)		((dd)->pdata->iv_ofs + ((x) * 0x04))
+
+#define DES_REG_CTRL(dd)		((dd)->pdata->ctrl_ofs)
+#define DES_REG_CTRL_CBC		BIT(4)
+#define DES_REG_CTRL_TDES		BIT(3)
+#define DES_REG_CTRL_DIRECTION		BIT(2)
+#define DES_REG_CTRL_INPUT_READY	BIT(1)
+#define DES_REG_CTRL_OUTPUT_READY	BIT(0)
+
+#define DES_REG_DATA_N(dd, x)		((dd)->pdata->data_ofs + ((x) * 0x04))
+
+#define DES_REG_REV(dd)			((dd)->pdata->rev_ofs)
+
+#define DES_REG_MASK(dd)		((dd)->pdata->mask_ofs)
+
+#define DES_REG_LENGTH_N(x)		(0x24 + ((x) * 0x04))
+
+#define DES_REG_IRQ_STATUS(dd)         ((dd)->pdata->irq_status_ofs)
+#define DES_REG_IRQ_ENABLE(dd)         ((dd)->pdata->irq_enable_ofs)
+#define DES_REG_IRQ_DATA_IN            BIT(1)
+#define DES_REG_IRQ_DATA_OUT           BIT(2)
+
+#define FLAGS_MODE_MASK		0x000f
+#define FLAGS_ENCRYPT		BIT(0)
+#define FLAGS_CBC		BIT(1)
+#define FLAGS_INIT		BIT(4)
+#define FLAGS_BUSY		BIT(6)
+
+struct omap_des_ctx {
+	struct omap_des_dev *dd;
+
+	int		keylen;
+	u32		key[(3 * DES_KEY_SIZE) / sizeof(u32)];
+	unsigned long	flags;
+};
+
+struct omap_des_reqctx {
+	unsigned long mode;
+};
+
+#define OMAP_DES_QUEUE_LENGTH	1
+#define OMAP_DES_CACHE_SIZE	0
+
+struct omap_des_algs_info {
+	struct crypto_alg	*algs_list;
+	unsigned int		size;
+	unsigned int		registered;
+};
+
+struct omap_des_pdata {
+	struct omap_des_algs_info	*algs_info;
+	unsigned int	algs_info_size;
+
+	void		(*trigger)(struct omap_des_dev *dd, int length);
+
+	u32		key_ofs;
+	u32		iv_ofs;
+	u32		ctrl_ofs;
+	u32		data_ofs;
+	u32		rev_ofs;
+	u32		mask_ofs;
+	u32             irq_enable_ofs;
+	u32             irq_status_ofs;
+
+	u32		dma_enable_in;
+	u32		dma_enable_out;
+	u32		dma_start;
+
+	u32		major_mask;
+	u32		major_shift;
+	u32		minor_mask;
+	u32		minor_shift;
+};
+
+struct omap_des_dev {
+	struct list_head	list;
+	unsigned long		phys_base;
+	void __iomem		*io_base;
+	struct omap_des_ctx	*ctx;
+	struct device		*dev;
+	unsigned long		flags;
+	int			err;
+
+	/* spinlock used for queues */
+	spinlock_t		lock;
+	struct crypto_queue	queue;
+
+	struct tasklet_struct	done_task;
+	struct tasklet_struct	queue_task;
+
+	struct ablkcipher_request	*req;
+	/*
+	 * total is used by PIO mode for book keeping so introduce
+	 * variable total_save as need it to calc page_order
+	 */
+	size_t                          total;
+	size_t                          total_save;
+
+	struct scatterlist		*in_sg;
+	struct scatterlist		*out_sg;
+
+	/* Buffers for copying for unaligned cases */
+	struct scatterlist		in_sgl;
+	struct scatterlist		out_sgl;
+	struct scatterlist		*orig_out;
+	int				sgs_copied;
+
+	struct scatter_walk		in_walk;
+	struct scatter_walk		out_walk;
+	int			dma_in;
+	struct dma_chan		*dma_lch_in;
+	int			dma_out;
+	struct dma_chan		*dma_lch_out;
+	int			in_sg_len;
+	int			out_sg_len;
+	int			pio_only;
+	const struct omap_des_pdata	*pdata;
+};
+
+/* keep registered devices data here */
+static LIST_HEAD(dev_list);
+static DEFINE_SPINLOCK(list_lock);
+
+#ifdef DEBUG
+#define omap_des_read(dd, offset)                               \
+	({                                                              \
+	 int _read_ret;                                          \
+	 _read_ret = __raw_readl(dd->io_base + offset);          \
+	 pr_err("omap_des_read(" #offset "=%#x)= %#x\n",       \
+		 offset, _read_ret);                            \
+	 _read_ret;                                              \
+	 })
+#else
+static inline u32 omap_des_read(struct omap_des_dev *dd, u32 offset)
+{
+	return __raw_readl(dd->io_base + offset);
+}
+#endif
+
+#ifdef DEBUG
+#define omap_des_write(dd, offset, value)                               \
+	do {                                                            \
+		pr_err("omap_des_write(" #offset "=%#x) value=%#x\n", \
+				offset, value);                                \
+		__raw_writel(value, dd->io_base + offset);              \
+	} while (0)
+#else
+static inline void omap_des_write(struct omap_des_dev *dd, u32 offset,
+		u32 value)
+{
+	__raw_writel(value, dd->io_base + offset);
+}
+#endif
+
+static inline void omap_des_write_mask(struct omap_des_dev *dd, u32 offset,
+					u32 value, u32 mask)
+{
+	u32 val;
+
+	val = omap_des_read(dd, offset);
+	val &= ~mask;
+	val |= value;
+	omap_des_write(dd, offset, val);
+}
+
+static void omap_des_write_n(struct omap_des_dev *dd, u32 offset,
+					u32 *value, int count)
+{
+	for (; count--; value++, offset += 4)
+		omap_des_write(dd, offset, *value);
+}
+
+static int omap_des_hw_init(struct omap_des_dev *dd)
+{
+	/*
+	 * clocks are enabled when request starts and disabled when finished.
+	 * It may be long delays between requests.
+	 * Device might go to off mode to save power.
+	 */
+	pm_runtime_get_sync(dd->dev);
+
+	if (!(dd->flags & FLAGS_INIT)) {
+		dd->flags |= FLAGS_INIT;
+		dd->err = 0;
+	}
+
+	return 0;
+}
+
+static int omap_des_write_ctrl(struct omap_des_dev *dd)
+{
+	unsigned int key32;
+	int i, err;
+	u32 val = 0, mask = 0;
+
+	err = omap_des_hw_init(dd);
+	if (err)
+		return err;
+
+	key32 = dd->ctx->keylen / sizeof(u32);
+
+	/* it seems a key should always be set even if it has not changed */
+	for (i = 0; i < key32; i++) {
+		omap_des_write(dd, DES_REG_KEY(dd, i),
+			       __le32_to_cpu(dd->ctx->key[i]));
+	}
+
+	if ((dd->flags & FLAGS_CBC) && dd->req->info)
+		omap_des_write_n(dd, DES_REG_IV(dd, 0), dd->req->info, 2);
+
+	if (dd->flags & FLAGS_CBC)
+		val |= DES_REG_CTRL_CBC;
+	if (dd->flags & FLAGS_ENCRYPT)
+		val |= DES_REG_CTRL_DIRECTION;
+	if (key32 == 6)
+		val |= DES_REG_CTRL_TDES;
+
+	mask |= DES_REG_CTRL_CBC | DES_REG_CTRL_DIRECTION | DES_REG_CTRL_TDES;
+
+	omap_des_write_mask(dd, DES_REG_CTRL(dd), val, mask);
+
+	return 0;
+}
+
+static void omap_des_dma_trigger_omap4(struct omap_des_dev *dd, int length)
+{
+	u32 mask, val;
+
+	omap_des_write(dd, DES_REG_LENGTH_N(0), length);
+
+	val = dd->pdata->dma_start;
+
+	if (dd->dma_lch_out != NULL)
+		val |= dd->pdata->dma_enable_out;
+	if (dd->dma_lch_in != NULL)
+		val |= dd->pdata->dma_enable_in;
+
+	mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+	       dd->pdata->dma_start;
+
+	omap_des_write_mask(dd, DES_REG_MASK(dd), val, mask);
+}
+
+static void omap_des_dma_stop(struct omap_des_dev *dd)
+{
+	u32 mask;
+
+	mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
+	       dd->pdata->dma_start;
+
+	omap_des_write_mask(dd, DES_REG_MASK(dd), 0, mask);
+}
+
+static struct omap_des_dev *omap_des_find_dev(struct omap_des_ctx *ctx)
+{
+	struct omap_des_dev *dd = NULL, *tmp;
+
+	spin_lock_bh(&list_lock);
+	if (!ctx->dd) {
+		list_for_each_entry(tmp, &dev_list, list) {
+			/* FIXME: take fist available des core */
+			dd = tmp;
+			break;
+		}
+		ctx->dd = dd;
+	} else {
+		/* already found before */
+		dd = ctx->dd;
+	}
+	spin_unlock_bh(&list_lock);
+
+	return dd;
+}
+
+static void omap_des_dma_out_callback(void *data)
+{
+	struct omap_des_dev *dd = data;
+
+	/* dma_lch_out - completed */
+	tasklet_schedule(&dd->done_task);
+}
+
+static int omap_des_dma_init(struct omap_des_dev *dd)
+{
+	int err = -ENOMEM;
+	dma_cap_mask_t mask;
+
+	dd->dma_lch_out = NULL;
+	dd->dma_lch_in = NULL;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	dd->dma_lch_in = dma_request_slave_channel_compat(mask,
+							  omap_dma_filter_fn,
+							  &dd->dma_in,
+							  dd->dev, "rx");
+	if (!dd->dma_lch_in) {
+		dev_err(dd->dev, "Unable to request in DMA channel\n");
+		goto err_dma_in;
+	}
+
+	dd->dma_lch_out = dma_request_slave_channel_compat(mask,
+							   omap_dma_filter_fn,
+							   &dd->dma_out,
+							   dd->dev, "tx");
+	if (!dd->dma_lch_out) {
+		dev_err(dd->dev, "Unable to request out DMA channel\n");
+		goto err_dma_out;
+	}
+
+	return 0;
+
+err_dma_out:
+	dma_release_channel(dd->dma_lch_in);
+err_dma_in:
+	if (err)
+		pr_err("error: %d\n", err);
+	return err;
+}
+
+static void omap_des_dma_cleanup(struct omap_des_dev *dd)
+{
+	dma_release_channel(dd->dma_lch_out);
+	dma_release_channel(dd->dma_lch_in);
+}
+
+static void sg_copy_buf(void *buf, struct scatterlist *sg,
+			      unsigned int start, unsigned int nbytes, int out)
+{
+	struct scatter_walk walk;
+
+	if (!nbytes)
+		return;
+
+	scatterwalk_start(&walk, sg);
+	scatterwalk_advance(&walk, start);
+	scatterwalk_copychunks(buf, &walk, nbytes, out);
+	scatterwalk_done(&walk, out, 0);
+}
+
+static int omap_des_crypt_dma(struct crypto_tfm *tfm,
+		struct scatterlist *in_sg, struct scatterlist *out_sg,
+		int in_sg_len, int out_sg_len)
+{
+	struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct omap_des_dev *dd = ctx->dd;
+	struct dma_async_tx_descriptor *tx_in, *tx_out;
+	struct dma_slave_config cfg;
+	int ret;
+
+	if (dd->pio_only) {
+		scatterwalk_start(&dd->in_walk, dd->in_sg);
+		scatterwalk_start(&dd->out_walk, dd->out_sg);
+
+		/* Enable DATAIN interrupt and let it take
+		   care of the rest */
+		omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
+		return 0;
+	}
+
+	dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE);
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.src_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
+	cfg.dst_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
+	cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	cfg.src_maxburst = DST_MAXBURST;
+	cfg.dst_maxburst = DST_MAXBURST;
+
+	/* IN */
+	ret = dmaengine_slave_config(dd->dma_lch_in, &cfg);
+	if (ret) {
+		dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
+			ret);
+		return ret;
+	}
+
+	tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len,
+					DMA_MEM_TO_DEV,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!tx_in) {
+		dev_err(dd->dev, "IN prep_slave_sg() failed\n");
+		return -EINVAL;
+	}
+
+	/* No callback necessary */
+	tx_in->callback_param = dd;
+
+	/* OUT */
+	ret = dmaengine_slave_config(dd->dma_lch_out, &cfg);
+	if (ret) {
+		dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
+			ret);
+		return ret;
+	}
+
+	tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len,
+					DMA_DEV_TO_MEM,
+					DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+	if (!tx_out) {
+		dev_err(dd->dev, "OUT prep_slave_sg() failed\n");
+		return -EINVAL;
+	}
+
+	tx_out->callback = omap_des_dma_out_callback;
+	tx_out->callback_param = dd;
+
+	dmaengine_submit(tx_in);
+	dmaengine_submit(tx_out);
+
+	dma_async_issue_pending(dd->dma_lch_in);
+	dma_async_issue_pending(dd->dma_lch_out);
+
+	/* start DMA */
+	dd->pdata->trigger(dd, dd->total);
+
+	return 0;
+}
+
+static int omap_des_crypt_dma_start(struct omap_des_dev *dd)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+					crypto_ablkcipher_reqtfm(dd->req));
+	int err;
+
+	pr_debug("total: %d\n", dd->total);
+
+	if (!dd->pio_only) {
+		err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len,
+				 DMA_TO_DEVICE);
+		if (!err) {
+			dev_err(dd->dev, "dma_map_sg() error\n");
+			return -EINVAL;
+		}
+
+		err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+				 DMA_FROM_DEVICE);
+		if (!err) {
+			dev_err(dd->dev, "dma_map_sg() error\n");
+			return -EINVAL;
+		}
+	}
+
+	err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len,
+				 dd->out_sg_len);
+	if (err && !dd->pio_only) {
+		dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+		dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+			     DMA_FROM_DEVICE);
+	}
+
+	return err;
+}
+
+static void omap_des_finish_req(struct omap_des_dev *dd, int err)
+{
+	struct ablkcipher_request *req = dd->req;
+
+	pr_debug("err: %d\n", err);
+
+	pm_runtime_put(dd->dev);
+	dd->flags &= ~FLAGS_BUSY;
+
+	req->base.complete(&req->base, err);
+}
+
+static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
+{
+	int err = 0;
+
+	pr_debug("total: %d\n", dd->total);
+
+	omap_des_dma_stop(dd);
+
+	dmaengine_terminate_all(dd->dma_lch_in);
+	dmaengine_terminate_all(dd->dma_lch_out);
+
+	dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+	dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE);
+
+	return err;
+}
+
+int omap_des_copy_needed(struct scatterlist *sg)
+{
+	while (sg) {
+		if (!IS_ALIGNED(sg->offset, 4))
+			return -1;
+		if (!IS_ALIGNED(sg->length, DES_BLOCK_SIZE))
+			return -1;
+		sg = sg_next(sg);
+	}
+	return 0;
+}
+
+int omap_des_copy_sgs(struct omap_des_dev *dd)
+{
+	void *buf_in, *buf_out;
+	int pages;
+
+	pages = dd->total >> PAGE_SHIFT;
+
+	if (dd->total & (PAGE_SIZE-1))
+		pages++;
+
+	BUG_ON(!pages);
+
+	buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages);
+	buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages);
+
+	if (!buf_in || !buf_out) {
+		pr_err("Couldn't allocated pages for unaligned cases.\n");
+		return -1;
+	}
+
+	dd->orig_out = dd->out_sg;
+
+	sg_copy_buf(buf_in, dd->in_sg, 0, dd->total, 0);
+
+	sg_init_table(&dd->in_sgl, 1);
+	sg_set_buf(&dd->in_sgl, buf_in, dd->total);
+	dd->in_sg = &dd->in_sgl;
+
+	sg_init_table(&dd->out_sgl, 1);
+	sg_set_buf(&dd->out_sgl, buf_out, dd->total);
+	dd->out_sg = &dd->out_sgl;
+
+	return 0;
+}
+
+static int omap_des_handle_queue(struct omap_des_dev *dd,
+			       struct ablkcipher_request *req)
+{
+	struct crypto_async_request *async_req, *backlog;
+	struct omap_des_ctx *ctx;
+	struct omap_des_reqctx *rctx;
+	unsigned long flags;
+	int err, ret = 0;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	if (req)
+		ret = ablkcipher_enqueue_request(&dd->queue, req);
+	if (dd->flags & FLAGS_BUSY) {
+		spin_unlock_irqrestore(&dd->lock, flags);
+		return ret;
+	}
+	backlog = crypto_get_backlog(&dd->queue);
+	async_req = crypto_dequeue_request(&dd->queue);
+	if (async_req)
+		dd->flags |= FLAGS_BUSY;
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	if (!async_req)
+		return ret;
+
+	if (backlog)
+		backlog->complete(backlog, -EINPROGRESS);
+
+	req = ablkcipher_request_cast(async_req);
+
+	/* assign new request to device */
+	dd->req = req;
+	dd->total = req->nbytes;
+	dd->total_save = req->nbytes;
+	dd->in_sg = req->src;
+	dd->out_sg = req->dst;
+
+	if (omap_des_copy_needed(dd->in_sg) ||
+	    omap_des_copy_needed(dd->out_sg)) {
+		if (omap_des_copy_sgs(dd))
+			pr_err("Failed to copy SGs for unaligned cases\n");
+		dd->sgs_copied = 1;
+	} else {
+		dd->sgs_copied = 0;
+	}
+
+	dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total);
+	dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total);
+	BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0);
+
+	rctx = ablkcipher_request_ctx(req);
+	ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
+	rctx->mode &= FLAGS_MODE_MASK;
+	dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
+
+	dd->ctx = ctx;
+	ctx->dd = dd;
+
+	err = omap_des_write_ctrl(dd);
+	if (!err)
+		err = omap_des_crypt_dma_start(dd);
+	if (err) {
+		/* des_task will not finish it, so do it here */
+		omap_des_finish_req(dd, err);
+		tasklet_schedule(&dd->queue_task);
+	}
+
+	return ret; /* return ret, which is enqueue return value */
+}
+
+static void omap_des_done_task(unsigned long data)
+{
+	struct omap_des_dev *dd = (struct omap_des_dev *)data;
+	void *buf_in, *buf_out;
+	int pages;
+
+	pr_debug("enter done_task\n");
+
+	if (!dd->pio_only) {
+		dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
+				       DMA_FROM_DEVICE);
+		dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
+		dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
+			     DMA_FROM_DEVICE);
+		omap_des_crypt_dma_stop(dd);
+	}
+
+	if (dd->sgs_copied) {
+		buf_in = sg_virt(&dd->in_sgl);
+		buf_out = sg_virt(&dd->out_sgl);
+
+		sg_copy_buf(buf_out, dd->orig_out, 0, dd->total_save, 1);
+
+		pages = get_order(dd->total_save);
+		free_pages((unsigned long)buf_in, pages);
+		free_pages((unsigned long)buf_out, pages);
+	}
+
+	omap_des_finish_req(dd, 0);
+	omap_des_handle_queue(dd, NULL);
+
+	pr_debug("exit\n");
+}
+
+static void omap_des_queue_task(unsigned long data)
+{
+	struct omap_des_dev *dd = (struct omap_des_dev *)data;
+
+	omap_des_handle_queue(dd, NULL);
+}
+
+static int omap_des_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+	struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(
+			crypto_ablkcipher_reqtfm(req));
+	struct omap_des_reqctx *rctx = ablkcipher_request_ctx(req);
+	struct omap_des_dev *dd;
+
+	pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->nbytes,
+		 !!(mode & FLAGS_ENCRYPT),
+		 !!(mode & FLAGS_CBC));
+
+	if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
+		pr_err("request size is not exact amount of DES blocks\n");
+		return -EINVAL;
+	}
+
+	dd = omap_des_find_dev(ctx);
+	if (!dd)
+		return -ENODEV;
+
+	rctx->mode = mode;
+
+	return omap_des_handle_queue(dd, req);
+}
+
+/* ********************** ALG API ************************************ */
+
+static int omap_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+			   unsigned int keylen)
+{
+	struct omap_des_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+
+	if (keylen != DES_KEY_SIZE && keylen != (3*DES_KEY_SIZE))
+		return -EINVAL;
+
+	pr_debug("enter, keylen: %d\n", keylen);
+
+	memcpy(ctx->key, key, keylen);
+	ctx->keylen = keylen;
+
+	return 0;
+}
+
+static int omap_des_ecb_encrypt(struct ablkcipher_request *req)
+{
+	return omap_des_crypt(req, FLAGS_ENCRYPT);
+}
+
+static int omap_des_ecb_decrypt(struct ablkcipher_request *req)
+{
+	return omap_des_crypt(req, 0);
+}
+
+static int omap_des_cbc_encrypt(struct ablkcipher_request *req)
+{
+	return omap_des_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
+}
+
+static int omap_des_cbc_decrypt(struct ablkcipher_request *req)
+{
+	return omap_des_crypt(req, FLAGS_CBC);
+}
+
+static int omap_des_cra_init(struct crypto_tfm *tfm)
+{
+	pr_debug("enter\n");
+
+	tfm->crt_ablkcipher.reqsize = sizeof(struct omap_des_reqctx);
+
+	return 0;
+}
+
+static void omap_des_cra_exit(struct crypto_tfm *tfm)
+{
+	pr_debug("enter\n");
+}
+
+/* ********************** ALGS ************************************ */
+
+static struct crypto_alg algs_ecb_cbc[] = {
+{
+	.cra_name		= "ecb(des)",
+	.cra_driver_name	= "ecb-des-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_KERN_DRIVER_ONLY |
+				  CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_des_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_des_cra_init,
+	.cra_exit		= omap_des_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES_KEY_SIZE,
+		.max_keysize	= DES_KEY_SIZE,
+		.setkey		= omap_des_setkey,
+		.encrypt	= omap_des_ecb_encrypt,
+		.decrypt	= omap_des_ecb_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(des)",
+	.cra_driver_name	= "cbc-des-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_KERN_DRIVER_ONLY |
+				  CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_des_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_des_cra_init,
+	.cra_exit		= omap_des_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= DES_KEY_SIZE,
+		.max_keysize	= DES_KEY_SIZE,
+		.ivsize		= DES_BLOCK_SIZE,
+		.setkey		= omap_des_setkey,
+		.encrypt	= omap_des_cbc_encrypt,
+		.decrypt	= omap_des_cbc_decrypt,
+	}
+},
+{
+	.cra_name		= "ecb(des3_ede)",
+	.cra_driver_name	= "ecb-des3-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_KERN_DRIVER_ONLY |
+				  CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_des_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_des_cra_init,
+	.cra_exit		= omap_des_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= 3*DES_KEY_SIZE,
+		.max_keysize	= 3*DES_KEY_SIZE,
+		.setkey		= omap_des_setkey,
+		.encrypt	= omap_des_ecb_encrypt,
+		.decrypt	= omap_des_ecb_decrypt,
+	}
+},
+{
+	.cra_name		= "cbc(des3_ede)",
+	.cra_driver_name	= "cbc-des3-omap",
+	.cra_priority		= 100,
+	.cra_flags		= CRYPTO_ALG_TYPE_ABLKCIPHER |
+				  CRYPTO_ALG_KERN_DRIVER_ONLY |
+				  CRYPTO_ALG_ASYNC,
+	.cra_blocksize		= DES_BLOCK_SIZE,
+	.cra_ctxsize		= sizeof(struct omap_des_ctx),
+	.cra_alignmask		= 0,
+	.cra_type		= &crypto_ablkcipher_type,
+	.cra_module		= THIS_MODULE,
+	.cra_init		= omap_des_cra_init,
+	.cra_exit		= omap_des_cra_exit,
+	.cra_u.ablkcipher = {
+		.min_keysize	= 3*DES_KEY_SIZE,
+		.max_keysize	= 3*DES_KEY_SIZE,
+		.ivsize		= DES_BLOCK_SIZE,
+		.setkey		= omap_des_setkey,
+		.encrypt	= omap_des_cbc_encrypt,
+		.decrypt	= omap_des_cbc_decrypt,
+	}
+}
+};
+
+static struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = {
+	{
+		.algs_list	= algs_ecb_cbc,
+		.size		= ARRAY_SIZE(algs_ecb_cbc),
+	},
+};
+
+#ifdef CONFIG_OF
+static const struct omap_des_pdata omap_des_pdata_omap4 = {
+	.algs_info	= omap_des_algs_info_ecb_cbc,
+	.algs_info_size	= ARRAY_SIZE(omap_des_algs_info_ecb_cbc),
+	.trigger	= omap_des_dma_trigger_omap4,
+	.key_ofs	= 0x14,
+	.iv_ofs		= 0x18,
+	.ctrl_ofs	= 0x20,
+	.data_ofs	= 0x28,
+	.rev_ofs	= 0x30,
+	.mask_ofs	= 0x34,
+	.irq_status_ofs = 0x3c,
+	.irq_enable_ofs = 0x40,
+	.dma_enable_in	= BIT(5),
+	.dma_enable_out	= BIT(6),
+	.major_mask	= 0x0700,
+	.major_shift	= 8,
+	.minor_mask	= 0x003f,
+	.minor_shift	= 0,
+};
+
+static irqreturn_t omap_des_irq(int irq, void *dev_id)
+{
+	struct omap_des_dev *dd = dev_id;
+	u32 status, i;
+	u32 *src, *dst;
+
+	status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd));
+	if (status & DES_REG_IRQ_DATA_IN) {
+		omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
+
+		BUG_ON(!dd->in_sg);
+
+		BUG_ON(_calc_walked(in) > dd->in_sg->length);
+
+		src = sg_virt(dd->in_sg) + _calc_walked(in);
+
+		for (i = 0; i < DES_BLOCK_WORDS; i++) {
+			omap_des_write(dd, DES_REG_DATA_N(dd, i), *src);
+
+			scatterwalk_advance(&dd->in_walk, 4);
+			if (dd->in_sg->length == _calc_walked(in)) {
+				dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+				if (dd->in_sg) {
+					scatterwalk_start(&dd->in_walk,
+							  dd->in_sg);
+					src = sg_virt(dd->in_sg) +
+					      _calc_walked(in);
+				}
+			} else {
+				src++;
+			}
+		}
+
+		/* Clear IRQ status */
+		status &= ~DES_REG_IRQ_DATA_IN;
+		omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
+
+		/* Enable DATA_OUT interrupt */
+		omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4);
+
+	} else if (status & DES_REG_IRQ_DATA_OUT) {
+		omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
+
+		BUG_ON(!dd->out_sg);
+
+		BUG_ON(_calc_walked(out) > dd->out_sg->length);
+
+		dst = sg_virt(dd->out_sg) + _calc_walked(out);
+
+		for (i = 0; i < DES_BLOCK_WORDS; i++) {
+			*dst = omap_des_read(dd, DES_REG_DATA_N(dd, i));
+			scatterwalk_advance(&dd->out_walk, 4);
+			if (dd->out_sg->length == _calc_walked(out)) {
+				dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+				if (dd->out_sg) {
+					scatterwalk_start(&dd->out_walk,
+							  dd->out_sg);
+					dst = sg_virt(dd->out_sg) +
+					      _calc_walked(out);
+				}
+			} else {
+				dst++;
+			}
+		}
+
+		dd->total -= DES_BLOCK_SIZE;
+
+		BUG_ON(dd->total < 0);
+
+		/* Clear IRQ status */
+		status &= ~DES_REG_IRQ_DATA_OUT;
+		omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
+
+		if (!dd->total)
+			/* All bytes read! */
+			tasklet_schedule(&dd->done_task);
+		else
+			/* Enable DATA_IN interrupt for next block */
+			omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static const struct of_device_id omap_des_of_match[] = {
+	{
+		.compatible	= "ti,omap4-des",
+		.data		= &omap_des_pdata_omap4,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_des_of_match);
+
+static int omap_des_get_of(struct omap_des_dev *dd,
+		struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(omap_des_of_match), &pdev->dev);
+	if (!match) {
+		dev_err(&pdev->dev, "no compatible OF match\n");
+		return -EINVAL;
+	}
+
+	dd->dma_out = -1; /* Dummy value that's unused */
+	dd->dma_in = -1; /* Dummy value that's unused */
+	dd->pdata = match->data;
+
+	return 0;
+}
+#else
+static int omap_des_get_of(struct omap_des_dev *dd,
+		struct device *dev)
+{
+	return -EINVAL;
+}
+#endif
+
+static int omap_des_get_pdev(struct omap_des_dev *dd,
+		struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *r;
+	int err = 0;
+
+	/* Get the DMA out channel */
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!r) {
+		dev_err(dev, "no DMA out resource info\n");
+		err = -ENODEV;
+		goto err;
+	}
+	dd->dma_out = r->start;
+
+	/* Get the DMA in channel */
+	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!r) {
+		dev_err(dev, "no DMA in resource info\n");
+		err = -ENODEV;
+		goto err;
+	}
+	dd->dma_in = r->start;
+
+	/* non-DT devices get pdata from pdev */
+	dd->pdata = pdev->dev.platform_data;
+
+err:
+	return err;
+}
+
+static int omap_des_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct omap_des_dev *dd;
+	struct crypto_alg *algp;
+	struct resource *res;
+	int err = -ENOMEM, i, j, irq = -1;
+	u32 reg;
+
+	dd = devm_kzalloc(dev, sizeof(struct omap_des_dev), GFP_KERNEL);
+	if (dd == NULL) {
+		dev_err(dev, "unable to alloc data struct.\n");
+		goto err_data;
+	}
+	dd->dev = dev;
+	platform_set_drvdata(pdev, dd);
+
+	spin_lock_init(&dd->lock);
+	crypto_init_queue(&dd->queue, OMAP_DES_QUEUE_LENGTH);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no MEM resource info\n");
+		goto err_res;
+	}
+
+	err = (dev->of_node) ? omap_des_get_of(dd, pdev) :
+			       omap_des_get_pdev(dd, pdev);
+	if (err)
+		goto err_res;
+
+	dd->io_base = devm_request_and_ioremap(dev, res);
+	if (!dd->io_base) {
+		dev_err(dev, "can't ioremap\n");
+		err = -ENOMEM;
+		goto err_res;
+	}
+	dd->phys_base = res->start;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	omap_des_dma_stop(dd);
+
+	reg = omap_des_read(dd, DES_REG_REV(dd));
+
+	pm_runtime_put_sync(dev);
+
+	dev_info(dev, "OMAP DES hw accel rev: %u.%u\n",
+		 (reg & dd->pdata->major_mask) >> dd->pdata->major_shift,
+		 (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
+
+	tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd);
+	tasklet_init(&dd->queue_task, omap_des_queue_task, (unsigned long)dd);
+
+	err = omap_des_dma_init(dd);
+	if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
+		dd->pio_only = 1;
+
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(dev, "can't get IRQ resource\n");
+			goto err_irq;
+		}
+
+		err = devm_request_irq(dev, irq, omap_des_irq, 0,
+				dev_name(dev), dd);
+		if (err) {
+			dev_err(dev, "Unable to grab omap-des IRQ\n");
+			goto err_irq;
+		}
+	}
+
+
+	INIT_LIST_HEAD(&dd->list);
+	spin_lock(&list_lock);
+	list_add_tail(&dd->list, &dev_list);
+	spin_unlock(&list_lock);
+
+	for (i = 0; i < dd->pdata->algs_info_size; i++) {
+		for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
+			algp = &dd->pdata->algs_info[i].algs_list[j];
+
+			pr_debug("reg alg: %s\n", algp->cra_name);
+			INIT_LIST_HEAD(&algp->cra_list);
+
+			err = crypto_register_alg(algp);
+			if (err)
+				goto err_algs;
+
+			dd->pdata->algs_info[i].registered++;
+		}
+	}
+
+	return 0;
+err_algs:
+	for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+			crypto_unregister_alg(
+					&dd->pdata->algs_info[i].algs_list[j]);
+	if (!dd->pio_only)
+		omap_des_dma_cleanup(dd);
+err_irq:
+	tasklet_kill(&dd->done_task);
+	tasklet_kill(&dd->queue_task);
+	pm_runtime_disable(dev);
+err_res:
+	dd = NULL;
+err_data:
+	dev_err(dev, "initialization failed.\n");
+	return err;
+}
+
+static int omap_des_remove(struct platform_device *pdev)
+{
+	struct omap_des_dev *dd = platform_get_drvdata(pdev);
+	int i, j;
+
+	if (!dd)
+		return -ENODEV;
+
+	spin_lock(&list_lock);
+	list_del(&dd->list);
+	spin_unlock(&list_lock);
+
+	for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
+		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
+			crypto_unregister_alg(
+					&dd->pdata->algs_info[i].algs_list[j]);
+
+	tasklet_kill(&dd->done_task);
+	tasklet_kill(&dd->queue_task);
+	omap_des_dma_cleanup(dd);
+	pm_runtime_disable(dd->dev);
+	dd = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int omap_des_suspend(struct device *dev)
+{
+	pm_runtime_put_sync(dev);
+	return 0;
+}
+
+static int omap_des_resume(struct device *dev)
+{
+	pm_runtime_get_sync(dev);
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops omap_des_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(omap_des_suspend, omap_des_resume)
+};
+
+static struct platform_driver omap_des_driver = {
+	.probe	= omap_des_probe,
+	.remove	= omap_des_remove,
+	.driver	= {
+		.name	= "omap-des",
+		.owner	= THIS_MODULE,
+		.pm	= &omap_des_pm_ops,
+		.of_match_table	= of_match_ptr(omap_des_of_match),
+	},
+};
+
+module_platform_driver(omap_des_driver);
+
+MODULE_DESCRIPTION("OMAP DES hw acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Joel Fernandes <joelf@ti.com>");
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v2 2/2] crypto: omap-des: Add config and build options
From: Joel Fernandes @ 2014-02-14 16:49 UTC (permalink / raw)
  To: linux-arm-kernel

Add config and build options for the omap-des driver.

Signed-off-by: Joel Fernandes <joelf@ti.com>
---
 drivers/crypto/Kconfig  |   11 +++++++++++
 drivers/crypto/Makefile |    1 +
 2 files changed, 12 insertions(+)

diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 13857f5..8e38000 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -262,6 +262,17 @@ config CRYPTO_DEV_OMAP_AES
 	  OMAP processors have AES module accelerator. Select this if you
 	  want to use the OMAP module for AES algorithms.
 
+config CRYPTO_DEV_OMAP_DES
+	tristate "Support for OMAP DES3DES hw engine"
+	depends on ARCH_OMAP2PLUS
+	select CRYPTO_DES
+	select CRYPTO_BLKCIPHER2
+	help
+	  OMAP processors have DES/3DES module accelerator. Select this if you
+	  want to use the OMAP module for DES and 3DES algorithms. Currently
+	  the ECB and CBC modes of operation supported by the driver. Also
+	  accesses made on unaligned boundaries are also supported.
+
 config CRYPTO_DEV_PICOXCELL
 	tristate "Support for picoXcell IPSEC and Layer2 crypto engines"
 	depends on ARCH_PICOXCELL && HAVE_CLK
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 0bc6aa0..9a53fb8 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o
 n2_crypto-y := n2_core.o n2_asm.o
 obj-$(CONFIG_CRYPTO_DEV_NX) += nx/
 obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
+obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o
 obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v8 0/4] ARM: BCM5301X: initial support for the BCM5301X/BCM470X SoCs with ARM CPU
From: Florian Fainelli @ 2014-02-14 16:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1391468506-5800-1-git-send-email-hauke@hauke-m.de>

Hi Christian,

Le 03/02/2014 15:01, Hauke Mehrtens a ?crit :
> This adds initial support for Broadcom network SoC from the BCM5301X
> and BCM470X line.
>
> I do not have any documentation, only the vendor source code published
> by Asus and Netgear to conform with the GPL, it would be nice to get
> some documentation for this Soc like this
> https://www.broadcom.com/collateral/pg/440X-PG02-R.pdf
> for the Broadcom BCM440X Ethernet controller.
>
> With some additional patches I got Ethernet working with ~250 MBit/s.
>
> A bootlog can be found here:
> http://hauke-m.de/files/openwrt/devices/R6250/openwrt-boot-2014-01-05.txt
>
> This is based on 3.14-rc1.
>
> Christian Daudt could you please take these patches.

Christian, have you been able to get a look at those patches? How do you 
want to proceed for patches affecting bcm5301x in the future? Except for 
a few cases (Kconfig, Makefile), support for bcm5301x is orthogonal to 
the other bcm-mobile SoCs, should that be taken care of by the arm-soc 
maintainers directly?

Thanks!

>
> Changes since v7:
>   * reorder debug options
>   * rebase on 3.14-rc1
>
> Changes since v6:
>   * rebase on arm-soc.git branch next/soc
>   * use ranges in dts files for SoC blocks
>
> Changes since v5:
>   * restructured the dts files, own file for the SoC family, the SoC and
>     the device
>
> Changes since v4:
>   * removed bcm5301x_timer_init(), this function is not needed
>   * removed GENERIC_TIME this is dead
>   * made fault handler check for code and just catch the first fault.
>
> Changes since v3:
>   * rebase on Linus 3.13-rc7
>   * split the workaround into an own patch
>   * add L2 cache controller to Device tree
>   * rename config option
>   * add local-timer and SCU entry to device tree
>
> Changes since v2:
>   * use vendor prefix brcm
>   * move code to arch/arm/mach-bcm/
>   * cleanup arch/arm/mach-bcm/bcm5301x.c
>   * rename to bcm5301x
>   * split into more patches
>
> Changes since v1:
>   * add file Documentation/devicetree/bindings/arm/bcm4708.txt
>   * rename bcm5301x to bcm4708 in dts files
>   * use preprocessor includes in dts file
>   * add CONFIG_ARCH_BCM53XX to multi_v7_defconfig
>   * remove init_machine callback
>   * rename vendor prefix from brcm to bcm
>   * split into two patches
>
> Hauke Mehrtens (4):
>    ARM: BCM5301X: initial support for the BCM5301X/BCM470X SoCs with ARM
>      CPU
>    ARM: BCM5301X: add early debugging support
>    ARM: BCM5301X: add dts files for BCM4708 SoC
>    ARM: BCM5301X: workaround suppress fault
>
>   Documentation/devicetree/bindings/arm/bcm4708.txt |    8 ++
>   MAINTAINERS                                       |    8 ++
>   arch/arm/Kconfig.debug                            |    7 ++
>   arch/arm/boot/dts/Makefile                        |    1 +
>   arch/arm/boot/dts/bcm4708-netgear-r6250.dts       |   35 ++++++++
>   arch/arm/boot/dts/bcm4708.dtsi                    |   34 ++++++++
>   arch/arm/boot/dts/bcm5301x.dtsi                   |   95 +++++++++++++++++++++
>   arch/arm/configs/multi_v7_defconfig               |    1 +
>   arch/arm/mach-bcm/Kconfig                         |   26 ++++++
>   arch/arm/mach-bcm/Makefile                        |    1 +
>   arch/arm/mach-bcm/bcm_5301x.c                     |   61 +++++++++++++
>   11 files changed, 277 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/arm/bcm4708.txt
>   create mode 100644 arch/arm/boot/dts/bcm4708-netgear-r6250.dts
>   create mode 100644 arch/arm/boot/dts/bcm4708.dtsi
>   create mode 100644 arch/arm/boot/dts/bcm5301x.dtsi
>   create mode 100644 arch/arm/mach-bcm/bcm_5301x.c
>

^ permalink raw reply

* IPI_WAKEUP for arm64
From: Catalin Marinas @ 2014-02-14 16:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CADApbejdRvUPPwKYwhDw8RL0MZ3082Rh9g1203cY5n7TwRD7gA@mail.gmail.com>

On Fri, Feb 14, 2014 at 09:20:43AM +0800, Chao Xie wrote:
> Why for arm, there are IPI_WAKEUP support in smp.c while for arm64, it
> is removed.
> Is there any reason for that?

It's not needed.

-- 
Catalin

^ permalink raw reply

* [RFC PATCH 0/2] ARM: Switch back to L_PTE_WRITE
From: Steve Capper @ 2014-02-14 16:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,
This RFC switches both the short and long descriptors back to using
L_PTE_WRITE to represent a writable pte, rather than !L_PTE_RDONLY.

This allows us, for long descriptors, to distinguish between writable
clean ptes and read only ptes; fixing a few problems with huge pages,
and possibly other areas of code.
(For short descriptors the distinction was possible already due to the
separate Linux/hardware ptes).

I originally attempted to leave the short descriptor code alone and
only modify the long descriptors to use L_PTE_WRITE. This turned out
to be both overly complicated and confusing. So, I have instead
reverted:
    36bb94b ARM: pgtable: provide RDONLY page table bit rather than WRITE bit
And introduced a separate L_PTE_WRITE software bit for long descriptors.

This series has been tested on an Arndale board running 3.14-rc2, and
both short and long descriptors. The libhugetlbfs tests have passed for
LPAE. I am currently running a barrage of ltp tests for both short and
long descriptors.

Whilst testing this patch with libhugetlbfs, I came across a horrible
bug in the handling of huge_pte_write(). For LPAE, both L_PTE_DIRTY and
L_PTE_WRITE are in the upper 32 bits of the ptes. The huge_pte_write()
function downcasts the result of pte_write() to 32-bits, meaning that
huge_pte_write() always returned false! I've noticed this downcasting
to 32-bits taking place in the following functions:
  o gather_stats
  o huge_pte_dirty
  o huge_pte_write
  o make_migration_entry
(under arm64, the downcasting doesn't take place on the huge_pte_
functions as they use long, but the others use int....)

To fix this issue, I have added a double logical invert to pte_write()
and pte_dirty() when LPAE is enabled (in the second patch in this
series). This fixes the problem, but it's leaving me feeling rather
filthy. Any suggestions on a cleaner way around this would be very
welcome.

Cheers,
--
Steve

Steve Capper (2):
  arm: mm: Switch back to L_PTE_WRITE
  arm: mm: Double logical invert for LPAE pte_write(), pte_dirty()

 arch/arm/include/asm/pgtable-2level.h |  4 +++-
 arch/arm/include/asm/pgtable-3level.h | 18 ++++++++++++++++--
 arch/arm/include/asm/pgtable.h        | 36 +++++++++++++++++------------------
 arch/arm/mm/dump.c                    |  8 ++++----
 arch/arm/mm/mmu.c                     | 25 ++++++++++++------------
 arch/arm/mm/proc-macros.S             | 16 ++++++++--------
 arch/arm/mm/proc-v7-2level.S          |  6 +++---
 arch/arm/mm/proc-v7-3level.S          |  6 ++++--
 arch/arm/mm/proc-xscale.S             |  4 ++--
 9 files changed, 70 insertions(+), 53 deletions(-)

-- 
1.8.1.4

^ permalink raw reply

* [RFC PATCH 1/2] arm: mm: Switch back to L_PTE_WRITE
From: Steve Capper @ 2014-02-14 16:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392396913-13570-1-git-send-email-steve.capper@linaro.org>

For LPAE, we have the following means for encoding writable or dirty
ptes:
                              L_PTE_DIRTY       L_PTE_RDONLY
    !pte_dirty && !pte_write        0               1
    !pte_dirty && pte_write         0               1
    pte_dirty && !pte_write         1               1
    pte_dirty && pte_write          1               0

So we can't distinguish between writable clean ptes and read only
ptes. This can cause problems with ptes being incorrectly flagged as
read only when they are writable but not dirty.

This patch re-introduces the L_PTE_WRITE bit for both short descriptors
and long descriptors, by reverting:
  36bb94b ARM: pgtable: provide RDONLY page table bit rather than WRITE bit

For short descriptors the L_PTE_RDONLY bit is renamed to L_PTE_WRITE
and the pertinent logic changed. For long descriptors, L_PTE_WRITE is
implemented as a new software bit and L_PTE_RDONLY is renamed to
PTE_RDONLY to highlight the fact that it is a hardware bit.

Signed-off-by: Steve Capper <steve.capper@linaro.org>
---
 arch/arm/include/asm/pgtable-2level.h |  2 +-
 arch/arm/include/asm/pgtable-3level.h |  4 ++--
 arch/arm/include/asm/pgtable.h        | 36 +++++++++++++++++------------------
 arch/arm/mm/dump.c                    |  8 ++++----
 arch/arm/mm/mmu.c                     | 25 ++++++++++++------------
 arch/arm/mm/proc-macros.S             | 16 ++++++++--------
 arch/arm/mm/proc-v7-2level.S          |  6 +++---
 arch/arm/mm/proc-v7-3level.S          |  6 ++++--
 arch/arm/mm/proc-xscale.S             |  4 ++--
 9 files changed, 55 insertions(+), 52 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h
index dfff709..ca43b84 100644
--- a/arch/arm/include/asm/pgtable-2level.h
+++ b/arch/arm/include/asm/pgtable-2level.h
@@ -120,7 +120,7 @@
 #define L_PTE_YOUNG		(_AT(pteval_t, 1) << 1)
 #define L_PTE_FILE		(_AT(pteval_t, 1) << 2)	/* only when !PRESENT */
 #define L_PTE_DIRTY		(_AT(pteval_t, 1) << 6)
-#define L_PTE_RDONLY		(_AT(pteval_t, 1) << 7)
+#define L_PTE_WRITE		(_AT(pteval_t, 1) << 7)
 #define L_PTE_USER		(_AT(pteval_t, 1) << 8)
 #define L_PTE_XN		(_AT(pteval_t, 1) << 9)
 #define L_PTE_SHARED		(_AT(pteval_t, 1) << 10)	/* shared(v6), coherent(xsc3) */
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 03243f7..8a392ef 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -79,12 +79,12 @@
 #define L_PTE_PRESENT		(_AT(pteval_t, 3) << 0)		/* Present */
 #define L_PTE_FILE		(_AT(pteval_t, 1) << 2)		/* only when !PRESENT */
 #define L_PTE_USER		(_AT(pteval_t, 1) << 6)		/* AP[1] */
-#define L_PTE_RDONLY		(_AT(pteval_t, 1) << 7)		/* AP[2] */
+#define PTE_RDONLY		(_AT(pteval_t, 1) << 7)		/* AP[2] */
 #define L_PTE_SHARED		(_AT(pteval_t, 3) << 8)		/* SH[1:0], inner shareable */
 #define L_PTE_YOUNG		(_AT(pteval_t, 1) << 10)	/* AF */
 #define L_PTE_XN		(_AT(pteval_t, 1) << 54)	/* XN */
 #define L_PTE_DIRTY		(_AT(pteval_t, 1) << 55)	/* unused */
-#define L_PTE_SPECIAL		(_AT(pteval_t, 1) << 56)	/* unused */
+#define L_PTE_WRITE		(_AT(pteval_t, 1) << 56)
 #define L_PTE_NONE		(_AT(pteval_t, 1) << 57)	/* PROT_NONE */
 
 #define PMD_SECT_VALID		(_AT(pmdval_t, 1) << 0)
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 7d59b52..7a17611 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -88,13 +88,13 @@ extern pgprot_t		pgprot_s2_device;
 
 #define _MOD_PROT(p, b)	__pgprot(pgprot_val(p) | (b))
 
-#define PAGE_NONE		_MOD_PROT(pgprot_user, L_PTE_XN | L_PTE_RDONLY | L_PTE_NONE)
-#define PAGE_SHARED		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_XN)
-#define PAGE_SHARED_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER)
-#define PAGE_COPY		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
-#define PAGE_COPY_EXEC		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
-#define PAGE_READONLY		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
-#define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_RDONLY)
+#define PAGE_NONE		_MOD_PROT(pgprot_user, L_PTE_XN | L_PTE_NONE)
+#define PAGE_SHARED		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE | L_PTE_XN)
+#define PAGE_SHARED_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_WRITE)
+#define PAGE_COPY		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_XN)
+#define PAGE_COPY_EXEC		_MOD_PROT(pgprot_user, L_PTE_USER)
+#define PAGE_READONLY		_MOD_PROT(pgprot_user, L_PTE_USER | L_PTE_XN)
+#define PAGE_READONLY_EXEC	_MOD_PROT(pgprot_user, L_PTE_USER)
 #define PAGE_KERNEL		_MOD_PROT(pgprot_kernel, L_PTE_XN)
 #define PAGE_KERNEL_EXEC	pgprot_kernel
 #define PAGE_HYP		_MOD_PROT(pgprot_kernel, L_PTE_HYP)
@@ -102,13 +102,13 @@ extern pgprot_t		pgprot_s2_device;
 #define PAGE_S2			_MOD_PROT(pgprot_s2, L_PTE_S2_RDONLY)
 #define PAGE_S2_DEVICE		_MOD_PROT(pgprot_s2_device, L_PTE_S2_RDWR)
 
-#define __PAGE_NONE		__pgprot(_L_PTE_DEFAULT | L_PTE_RDONLY | L_PTE_XN | L_PTE_NONE)
-#define __PAGE_SHARED		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
-#define __PAGE_SHARED_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER)
-#define __PAGE_COPY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
-#define __PAGE_COPY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY)
-#define __PAGE_READONLY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY | L_PTE_XN)
-#define __PAGE_READONLY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_RDONLY)
+#define __PAGE_NONE		__pgprot(_L_PTE_DEFAULT | L_PTE_XN | L_PTE_NONE)
+#define __PAGE_SHARED		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE | L_PTE_XN)
+#define __PAGE_SHARED_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_WRITE)
+#define __PAGE_COPY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
+#define __PAGE_COPY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER)
+#define __PAGE_READONLY		__pgprot(_L_PTE_DEFAULT | L_PTE_USER | L_PTE_XN)
+#define __PAGE_READONLY_EXEC	__pgprot(_L_PTE_DEFAULT | L_PTE_USER)
 
 #define __pgprot_modify(prot,mask,bits)		\
 	__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
@@ -216,7 +216,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 
 #define pte_none(pte)		(!pte_val(pte))
 #define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)		(!(pte_val(pte) & L_PTE_RDONLY))
+#define pte_write(pte)		(pte_val(pte) & L_PTE_WRITE)
 #define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
 #define pte_exec(pte)		(!(pte_val(pte) & L_PTE_XN))
@@ -248,8 +248,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
-PTE_BIT_FUNC(wrprotect, |= L_PTE_RDONLY);
-PTE_BIT_FUNC(mkwrite,   &= ~L_PTE_RDONLY);
+PTE_BIT_FUNC(wrprotect, &= ~L_PTE_WRITE);
+PTE_BIT_FUNC(mkwrite,   |= L_PTE_WRITE);
 PTE_BIT_FUNC(mkclean,   &= ~L_PTE_DIRTY);
 PTE_BIT_FUNC(mkdirty,   |= L_PTE_DIRTY);
 PTE_BIT_FUNC(mkold,     &= ~L_PTE_YOUNG);
@@ -261,7 +261,7 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	const pteval_t mask = L_PTE_XN | L_PTE_RDONLY | L_PTE_USER |
+	const pteval_t mask = L_PTE_XN | L_PTE_WRITE | L_PTE_USER |
 		L_PTE_NONE | L_PTE_VALID;
 	pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
 	return pte;
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 2b3a564..715ca93 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -58,10 +58,10 @@ static const struct prot_bits pte_bits[] = {
 		.set	= "USR",
 		.clear	= "   ",
 	}, {
-		.mask	= L_PTE_RDONLY,
-		.val	= L_PTE_RDONLY,
-		.set	= "ro",
-		.clear	= "RW",
+		.mask	= L_PTE_WRITE,
+		.val	= L_PTE_WRITE,
+		.set	= "RW",
+		.clear	= "ro",
 	}, {
 		.mask	= L_PTE_XN,
 		.val	= L_PTE_XN,
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4f08c13..38f40df 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -231,7 +231,7 @@ __setup("noalign", noalign_setup);
 
 #endif /* ifdef CONFIG_CPU_CP15 / else */
 
-#define PROT_PTE_DEVICE		L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
+#define PROT_PTE_DEVICE		L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_WRITE|L_PTE_XN
 #define PROT_SECT_DEVICE	PMD_TYPE_SECT|PMD_SECT_AP_WRITE
 
 static struct mem_type mem_types[] = {
@@ -277,26 +277,26 @@ static struct mem_type mem_types[] = {
 	},
 #endif
 	[MT_LOW_VECTORS] = {
-		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_RDONLY,
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_USER,
 	},
 	[MT_HIGH_VECTORS] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_USER | L_PTE_RDONLY,
+				L_PTE_USER,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_USER,
 	},
 	[MT_MEMORY_RWX] = {
-		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_WRITE,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_RW] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-			     L_PTE_XN,
+				L_PTE_WRITE | L_PTE_XN,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
@@ -307,26 +307,27 @@ static struct mem_type mem_types[] = {
 	},
 	[MT_MEMORY_RWX_NONCACHED] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_MT_BUFFERABLE,
+				L_PTE_WRITE | L_PTE_MT_BUFFERABLE,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_RW_DTCM] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_XN,
+				L_PTE_WRITE | L_PTE_XN,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_RWX_ITCM] = {
-		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY,
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_WRITE,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_KERNEL,
 	},
 	[MT_MEMORY_RW_SO] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_MT_UNCACHED | L_PTE_XN,
+				L_PTE_MT_UNCACHED | L_PTE_WRITE | L_PTE_XN,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S |
 				PMD_SECT_UNCACHED | PMD_SECT_XN,
@@ -334,7 +335,7 @@ static struct mem_type mem_types[] = {
 	},
 	[MT_MEMORY_DMA_READY] = {
 		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-				L_PTE_XN,
+				L_PTE_WRITE | L_PTE_XN,
 		.prot_l1   = PMD_TYPE_TABLE,
 		.domain    = DOMAIN_KERNEL,
 	},
@@ -588,7 +589,7 @@ static void __init build_mem_type_table(void)
 
 	pgprot_user   = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
 	pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
-				 L_PTE_DIRTY | kern_pgprot);
+				 L_PTE_DIRTY | L_PTE_WRITE | kern_pgprot);
 	pgprot_s2  = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | s2_pgprot);
 	pgprot_s2_device  = __pgprot(s2_device_pgprot);
 	pgprot_hyp_device  = __pgprot(hyp_device_pgprot);
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index e3c48a3..c62fd89 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -97,7 +97,7 @@
 #error PTE shared bit mismatch
 #endif
 #if !defined (CONFIG_ARM_LPAE) && \
-	(L_PTE_XN+L_PTE_USER+L_PTE_RDONLY+L_PTE_DIRTY+L_PTE_YOUNG+\
+	(L_PTE_XN+L_PTE_USER+L_PTE_WRITE+L_PTE_DIRTY+L_PTE_YOUNG+\
 	 L_PTE_FILE+L_PTE_PRESENT) > L_PTE_SHARED
 #error Invalid Linux PTE bit settings
 #endif
@@ -152,9 +152,9 @@
 	and	r2, r1, #L_PTE_MT_MASK
 	ldr	r2, [ip, r2]
 
-	eor	r1, r1, #L_PTE_DIRTY
-	tst	r1, #L_PTE_DIRTY|L_PTE_RDONLY
-	orrne	r3, r3, #PTE_EXT_APX
+	tst	r1, #L_PTE_WRITE
+	tstne	r1, #L_PTE_DIRTY
+	orreq	r3, r3, #PTE_EXT_APX
 
 	tst	r1, #L_PTE_USER
 	orrne	r3, r3, #PTE_EXT_AP1
@@ -199,7 +199,7 @@
 	.macro	armv3_set_pte_ext wc_disable=1
 	str	r1, [r0], #2048			@ linux version
 
-	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY
+	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
 
 	bic	r2, r1, #PTE_SMALL_AP_MASK	@ keep C, B bits
 	bic	r2, r2, #PTE_TYPE_MASK
@@ -208,7 +208,7 @@
 	tst	r3, #L_PTE_USER			@ user?
 	orrne	r2, r2, #PTE_SMALL_AP_URO_SRW
 
-	tst	r3, #L_PTE_RDONLY | L_PTE_DIRTY	@ write and dirty?
+	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ write and dirty?
 	orreq	r2, r2, #PTE_SMALL_AP_UNO_SRW
 
 	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ present and young?
@@ -242,7 +242,7 @@
 	.macro	xscale_set_pte_ext_prologue
 	str	r1, [r0]			@ linux version
 
-	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY
+	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
 
 	bic	r2, r1, #PTE_SMALL_AP_MASK	@ keep C, B bits
 	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
@@ -250,7 +250,7 @@
 	tst	r3, #L_PTE_USER			@ user?
 	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
 
-	tst	r3, #L_PTE_RDONLY | L_PTE_DIRTY	@ write and dirty?
+	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ write and dirty?
 	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
 						@ combined with user -> user r/w
 	.endm
diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index bdd3be4..297fccf 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -84,9 +84,9 @@ ENTRY(cpu_v7_set_pte_ext)
 	tst	r1, #1 << 4
 	orrne	r3, r3, #PTE_EXT_TEX(1)
 
-	eor	r1, r1, #L_PTE_DIRTY
-	tst	r1, #L_PTE_RDONLY | L_PTE_DIRTY
-	orrne	r3, r3, #PTE_EXT_APX
+	tst	r1, #L_PTE_WRITE
+	tstne	r1, #L_PTE_DIRTY
+	orreq	r3, r3, #PTE_EXT_APX
 
 	tst	r1, #L_PTE_USER
 	orrne	r3, r3, #PTE_EXT_AP1
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 01a719e..7793b2e 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -78,8 +78,10 @@ ENTRY(cpu_v7_set_pte_ext)
 	tst	r3, #1 << (57 - 32)		@ L_PTE_NONE
 	bicne	r2, #L_PTE_VALID
 	bne	1f
-	tst	r3, #1 << (55 - 32)		@ L_PTE_DIRTY
-	orreq	r2, #L_PTE_RDONLY
+	bic	r2, #PTE_RDONLY
+	tst	r3, #1 << (56 - 32)		@ L_PTE_WRITE
+	tstne	r3, #1 << (55 - 32)		@ L_PTE_DIRTY
+	orreq	r2, #PTE_RDONLY
 1:	strd	r2, r3, [r0]
 	ALT_SMP(W(nop))
 	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index d19b1cf..d5b23e8 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -510,8 +510,8 @@ ENTRY(cpu_xscale_set_pte_ext)
 	@
 	@ Erratum 40: must set memory to write-through for user read-only pages
 	@
-	and	ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_RDONLY) & ~(4 << 2)
-	teq	ip, #L_PTE_MT_WRITEBACK | L_PTE_USER | L_PTE_RDONLY
+	and	ip, r1, #(L_PTE_MT_MASK | L_PTE_USER | L_PTE_WRITE) & ~(4 << 2)
+	teq	ip, #L_PTE_MT_WRITEBACK | L_PTE_USER
 
 	moveq	r1, #L_PTE_MT_WRITETHROUGH
 	and	r1, r1, #L_PTE_MT_MASK
-- 
1.8.1.4

^ permalink raw reply related

* [RFC PATCH 2/2] arm: mm: Double logical invert for LPAE pte_write(), pte_dirty()
From: Steve Capper @ 2014-02-14 16:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392396913-13570-1-git-send-email-steve.capper@linaro.org>

On LPAE, L_PTE_WRITE and L_PTE_DIRTY are in the upper 32-bits.
Unfortunately, results from pte_write() and pte_dirty() are downcast
to 32-bits by core code:
  o gather_stats
  o huge_pte_dirty
  o huge_pte_write
  o make_migration_entry

This patch adds a double logical invert to pte_write() and pte_dirty()
for LPAE to ensure that the lower 32-bits are set if true.

Signed-off-by: Steve Capper <steve.capper@linaro.org>
---
 arch/arm/include/asm/pgtable-2level.h |  2 ++
 arch/arm/include/asm/pgtable-3level.h | 14 ++++++++++++++
 arch/arm/include/asm/pgtable.h        |  2 --
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-2level.h b/arch/arm/include/asm/pgtable-2level.h
index ca43b84..7e8ebe7 100644
--- a/arch/arm/include/asm/pgtable-2level.h
+++ b/arch/arm/include/asm/pgtable-2level.h
@@ -162,6 +162,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 
 #define pmd_large(pmd)		(pmd_val(pmd) & 2)
 #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
+#define pte_write(pte)		(pte_val(pte) & L_PTE_WRITE)
+#define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
 
 #define copy_pmd(pmdpd,pmdps)		\
 	do {				\
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 8a392ef..62efcc5 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -135,6 +135,20 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * On LPAE, L_PTE_WRITE and L_PTE_DIRTY are in the upper 32-bits.
+ * Unfortunately, results from pte_write() and pte_dirty() are downcast
+ * to 32-bits by core code:
+ *  o gather_stats
+ *  o huge_pte_dirty
+ *  o huge_pte_write
+ *  o make_migration_entry
+ *
+ * Double logical invert to make sure lower 32-bits are set if true.
+ */
+#define pte_write(pte)		(!!(pte_val(pte) & L_PTE_WRITE))
+#define pte_dirty(pte)		(!!(pte_val(pte) & L_PTE_DIRTY))
+
 #define pud_none(pud)		(!pud_val(pud))
 #define pud_bad(pud)		(!(pud_val(pud) & 2))
 #define pud_present(pud)	(pud_val(pud))
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 7a17611..e94a616 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -216,8 +216,6 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 
 #define pte_none(pte)		(!pte_val(pte))
 #define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)		(pte_val(pte) & L_PTE_WRITE)
-#define pte_dirty(pte)		(pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)		(pte_val(pte) & L_PTE_YOUNG)
 #define pte_exec(pte)		(!(pte_val(pte) & L_PTE_XN))
 #define pte_special(pte)	(0)
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH v4 12/13] cpuidle: mvebu: Add initial CPU idle support for Armada 370/XP SoC
From: Lorenzo Pieralisi @ 2014-02-14 17:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1392312816-17657-13-git-send-email-gregory.clement@free-electrons.com>

On Thu, Feb 13, 2014 at 05:33:35PM +0000, Gregory CLEMENT wrote:

[...]

> diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c
> new file mode 100644
> index 000000000000..57c69812e79d
> --- /dev/null
> +++ b/drivers/cpuidle/cpuidle-armada-370-xp.c
> @@ -0,0 +1,120 @@
> +/*
> + * Marvell Armada 370 and Armada XP SoC cpuidle driver
> + *
> + * Copyright (C) 2013 Marvell
> + *
> + * Nadav Haklai <nadavh@marvell.com>
> + * Gregory CLEMENT <gregory.clement@free-electrons.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + *
> + * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
> + */
> +
> +#include <linux/cpu_pm.h>
> +#include <linux/cpuidle.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/suspend.h>
> +#include <asm/suspend.h>
> +#include <linux/smp.h>
> +#include <asm/cpuidle.h>
> +#include <asm/smp_plat.h>
> +#include <linux/platform_device.h>
> +#include <asm/cp15.h>
> +#include <asm/cacheflush.h>

You should order them <linux/...>, then <asm/...>

> +
> +#define ARMADA_370_XP_MAX_STATES	3

Is this macro really needed ?

> +#define ARMADA_370_XP_FLAG_DEEP_IDLE	0x10000
> +extern void armada_370_xp_pmsu_idle_prepare(bool deepidle);
> +extern void ll_clear_cpu_coherent(void);
> +extern void ll_set_cpu_coherent(void);
> +
> +noinline static int armada_370_xp_cpu_suspend(unsigned long deepidle)
> +{
> +	armada_370_xp_pmsu_idle_prepare(deepidle);
> +
> +	v7_exit_coherency_flush(all);

The macro above clears the C bit in SCTLR and exit coherency (clears SMP
bit in SCTLR), let's keep this in mind, see below.

> +	ll_clear_cpu_coherent();

And the macro above uses ldr/str exclusives, and this is done with MMU
on and off (on cold-boot before jumping to secondary_startup and also
before jumping to cpu_resume in armada_370_xp_cpu_resume).

Can you explain to me how load/store exclusives work on this platform ?

ARM ARM A3.4.5

"It is IMPLEMENTATION DEFINED whether LDREX and STREX operations can be
performed to a memory region with the Device or Strongly-ordered memory
attribute. Unless the implementation documentation explicitly states that
LDREX and STREX operations to a memory region with the Device or
Strongly-ordered attribute are permitted, the effect of such operations is
UNPREDICTABLE."

At least code must be commented and an explanation on why this works has
to be given.

> +
> +	dsb();
> +
> +	wfi();
> +
> +	ll_set_cpu_coherent();
> +
> +	asm volatile(
> +	"mrc	p15, 0, %0, c1, c0, 0 \n\t"
> +	"tst	%0, #(1 << 2) \n\t"
> +	"orreq	r0, %0, #(1 << 2) \n\t"
> +	"mcreq	p15, 0, %0, c1, c0, 0 \n\t"
> +	"isb	"
> +	: : "r" (0));

First of all, complex code like this must be commented.

Moreover, this sequence is wrong. If wfi completes the kernel would explode.

1) where is the SMP bit in SCTLR restored ?
2) where are tlbs flushed (ie processors run out of coherency for _some_
   time, so tlbs might be stale) ?

> +
> +	return 0;
> +}
> +
> +static int armada_370_xp_enter_idle(struct cpuidle_device *dev,
> +				struct cpuidle_driver *drv,
> +				int index)
> +{
> +	bool deepidle = false;
> +	cpu_pm_enter();
> +
> +	if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE)
> +		deepidle = true;
> +
> +	cpu_suspend(deepidle, armada_370_xp_cpu_suspend);
> +
> +	cpu_pm_exit();
> +
> +	return index;

You should check the cpu_suspend return value and demote the idle state
accordingly, if it failed.

Thanks,
Lorenzo

^ permalink raw reply

* [PATCH v3] ARM: mm: report both sections from PMD
From: Steve Capper @ 2014-02-14 17:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140213195230.GA15275@www.outflux.net>

On Thu, Feb 13, 2014 at 11:52:30AM -0800, Kees Cook wrote:
> On 2-level page table systems, the PMD has 2 section entries. Report
> these, otherwise ARM_PTDUMP will miss reporting permission changes on
> odd section boundaries.
> 
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
> v3:
>  - re-reorganize, drop use of pmd_sect; suggested by Catalin Marinas.
> v2:
>  - reorganize, suggested by Catalin Marinas.
> ---
>  arch/arm/mm/dump.c |    3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
> index 2b342177f5de..61cc78ae9f21 100644
> --- a/arch/arm/mm/dump.c
> +++ b/arch/arm/mm/dump.c
> @@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
>  			note_page(st, addr, 3, pmd_val(*pmd));
>  		else
>  			walk_pte(st, pmd, addr);
> +
> +		if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
> +			note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
>  	}
>  }
>  
> -- 
> 1.7.9.5

This picks up an odd megabyte aligned section on my Arndale board with
short descriptors on 3.14-rc2. Behaves as expected with long descriptors
too (does nothing).

FWIW:
Tested-by: Steve Capper <steve.capper@linaro.org>

Cheers,
-- 
Steve

> 
> 
> -- 
> Kees Cook
> Chrome OS Security
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 2/3] arm64: Add Kconfig option for Samsung GH7 SoC family
From: Arnd Bergmann @ 2014-02-14 17:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMgdDnSc=Y8i6JYeGewCh1RPYZ_AxocxKzSD265fa2-yrA@mail.gmail.com>

On Thursday 13 February 2014, Olof Johansson wrote:
> On Mon, Feb 10, 2014 at 6:52 PM, Kukjin Kim <kgene.kim@samsung.com> wrote:
> > On 02/13/14 04:14, Arnd Bergmann wrote:
> >> On Wednesday 12 February 2014 13:04:40 Kumar Gala wrote:
> > Basically, I agreed with Arnd's suggestion to use ARCH_SBSA. Or we need to
> > define level in Kconfig like ARCH_SBSA_L1 for level1. BTW, how about
> > compliant with SBSA Level1 and having some specific features?

My feeling is that we don't need to use the levels for Kconfig, although
we might want to use them DT compatible strings, even if it ends up looking
a little funny when you do 

	compatible = "arm,sbsa-l3", "arm,sbsa-l2", "arm,sbsa-l1";

> What kind of features are you expecting though? More IP
> blocks/devices? Those are just kernel config options to enable,
> ideally as modules.

Right, I think we can just put them into defconfig. No need to
"select" them from Kconfig since the extra options wouldn't be
required for booting or using the system.

	Arnd

^ permalink raw reply

* [BISECTED] ssh - Received disconnect from x.x.x.x: 2: Bad packet length 3149594624
From: Ivaylo Dimitrov @ 2014-02-14 17:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140214162458.GF21986@mudshark.cambridge.arm.com>



On 14.02.2014 18:24, Will Deacon wrote:
>
> You could try putting back the UNALIGNED_ACCESS in net/mac80211/rx.c and
> commenting out the skb->len = desc->length  - PLCP_HEADER_LENGTH;  line
> above.

This seems to fix the issue too, but I am afraid there is more to be 
done, as I see

Feb 14 18:33:46 Nokia-N900 kernel: [   88.599853] wlan0: authenticate 
with 00:23:cd:17:86:d0
Feb 14 18:33:46 Nokia-N900 kernel: [   88.781860] wlan0: send auth to 
00:23:cd:17:86:d0 (try 1/3)
Feb 14 18:33:46 Nokia-N900 kernel: [   88.799804] wlan0: authenticated
Feb 14 18:33:46 Nokia-N900 kernel: [   88.806243] wlan0: associating 
with AP with corrupt probe response
Feb 14 18:33:46 Nokia-N900 kernel: [   88.814544] wlan0: associate with 
00:23:cd:17:86:d0 (try 1/3)
Feb 14 18:33:46 Nokia-N900 kernel: [   88.826416] wlan0: RX AssocResp 
from 00:23:cd:17:86:d0 (capab=0x431 status=0 aid=2)

spit in dmesg log. AFAIR this is the first time I see "associating with 
AP with corrupt probe response" in dmesg, no matter of the kernel 
version. Despite of that error message, wlan seems to work as it should, 
so far. I guess we need the driver's author saying on the issue.

Thanks,
Ivo

^ permalink raw reply

* [PATCH] pinctrl: single: add low powr mode support
From: Tony Lindgren @ 2014-02-14 17:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdaMDRKXgMjtbnV8hhhuKYbNzSG1U7LYnD5WEDaUE4z8pg@mail.gmail.com>

* Linus Walleij <linus.walleij@linaro.org> [140204 12:20]:
> On Tue, Jan 28, 2014 at 8:20 AM, Chao Xie <chao.xie@marvell.com> wrote:
> 
> > From: Chao Xie <chao.xie@marvell.com>
> >
> > For some silicons, the pin configuration register can control
> > the output of the pin when the pad including the pin enter
> > low power mode.
> > For example, the pin can be "Drive 1", "Drive 0", "Float" when
> > the pad including the pin enter low power mode.
> > It is very useful when you want to control the power leakeage
> > when the SOC enter low power mode, and can save more power for
> > the low power mode.
> >
> > Signed-off-by: Chao Xie <chao.xie@marvell.com>
> 
> Looks similar to the other pin config stuff, patch applied
> unless Tony protests.

Seems fine to me:

Acked-by: Tony Lindgren <tony@atomide.com>

^ permalink raw reply

* [PATCH 3/6] irqchip: gic: use writel instead of dsb + writel_relaxed
From: Rob Herring @ 2014-02-14 17:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20140214164803.GG10590@arm.com>

On Fri, Feb 14, 2014 at 10:48 AM, Catalin Marinas
<catalin.marinas@arm.com> wrote:
> On Fri, Feb 14, 2014 at 04:30:39PM +0000, Will Deacon wrote:
>> Well, the results are in (*drum roll*)...
>>
>> On Fri, Feb 07, 2014 at 11:23:37AM +0000, Will Deacon wrote:
>> > On Thu, Feb 06, 2014 at 03:20:48PM +0000, Catalin Marinas wrote:
>> > > On Thu, Feb 06, 2014 at 01:26:44PM +0000, Will Deacon wrote:
>> > > > Ok, my reasoning is as follows:
>> > > >
>> > > >   - CPU0 tries to message CPU1. It writes to a location in normal memory,
>> > > >     then writes to the GICD to send the SGI
>> > > >
>> > > >   - We need to ensure that CPU1 observes the write to normal memory before
>> > > >     the write to GICD reaches the distributor. This is *not* about end-point
>> > > >     ordering (the usual non-coherent DMA example).
>> > > >
>> > > >   - A dmb ishst ensures that the two writes are observed in order by CPU1
>> > > >     (and, in fact, the inner-shareable domain containing CPU0).
>> > >
>> > > The last bullet point is not correct. DMB would only guarantee that the
>> > > two writes (memory and GICD) are observed by CPU1 if CPU1 actually read
>> > > the GICD (observability is defined for master accesses).
>> >
>> > Rather than attempt to solve this via email (your examples below are already
>> > getting hard to follow :), how about we sit down with $drink_of_choice and
>> > post back here with our conclusions?
>>
>> ... and it turns out that a dmb(ishst) is sufficient!
>
> Until we hear otherwise ;)

It is a shame that all this thought and effort will just end with
barrier related chicken bits getting set anyway. Maybe the
$drink_of_choice was worth it. ;)

Rob

^ permalink raw reply

* [PATCH 23/27] clocksource: sh_cmt: Add DT support
From: Magnus Damm @ 2014-02-14 17:22 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1790131.DSZsj6HrSK@avalon>

Hi Laurent,

On Sat, Feb 15, 2014 at 1:12 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> Hi Magnus,
>
> On Saturday 15 February 2014 01:01:30 Magnus Damm wrote:
>> On Sat, Feb 15, 2014 at 12:53 AM, Laurent Pinchart wrote:
>> > On Friday 14 February 2014 10:58:22 Mark Rutland wrote:
>> >> On Fri, Feb 14, 2014 at 01:00:01AM +0000, Laurent Pinchart wrote:
>> >> > +Channels Optional Properties:
>> >> > +
>> >> > +  - clock-source-rating: rating of the timer as a clock source device.
>> >> > +  - clock-event-rating: rating of the timer as a clock event device.
>> >>
>> >> This feels like a leak of Linux internals. Why do you need this?
>> >
>> > You're right, it is. The clock source and clock event ratings are
>> > currently configured through platform data, I'll need to find a way to
>> > compute them in the driver instead.
>>
>> That would be very good!
>
> Any pointer would be appreciated :-) How did you compute the various ratings
> used in platform data all over the place ?

Historically we used the rating to select between CMT and TMU. For
clock sources I suppose you also have the jiffy rating to consider.
And for the SMP parts we have ARM IP for TWD and arch timers that have
their ratings too. So you need to check all the timers on a particular
system and consider what you want to have operating by default. The
ARM IP timers should be preferred if available. For clock sources the
rule is probably the higher resolution the better.

>> > There's still one piece of Linux-specific data I need though, as I need to
>> > specify for each channel whether to use it as a clock source device, a
>> > clock event device, both of them or none. That's configuration
>> > information that needs to be provided somehow.
>>
>> I think you can decide clock source or clock event assignment based on
>> number of channels available. If you have only a single channel then both
>> clock event and clock source need to be supported. Otherwise use one channel
>> for clock source and the rest for clock events.
>
> That won't match the current situation. Look at CMT0 in r8a7790 for instance.
> There's two hardware channels available, and we only use the first one, for
> clock events only.

You are correct. The reason for that is that the CMT driver today is
optimized for combined clock event and clock source operation.

Historically the hardware it initially was written for (sh-mobile on
the SH arch) only had a single timer channel so combined operation was
required for tickless to work. But since you're asking how to allocate
channels then I propose checking numbers of channels available and go
from there. With that the r8a7790 support can only get better. =)

>> This is probably out of scope for this DT conversion, but it would be neat
>> if you somehow could specify the CPU affinity for a channel to tie a clock
>> event to an individual CPU core. This would make a a per-cpu timer unless
>> I'm mistaken. But that's more of a software policy than anything else.
>
> Yes, that's a configuration that needs to be specified somewhere. I don't know
> where though.

As long as you have per-channel interrupts described in DT you can
probably handle this in a generic way in the driver.

Thanks,

/ magnus

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox