Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] arm: Add BTB invalidation on switch_mm for Cortex-A9, A12, A15 and A17
From: Marc Zyngier @ 2018-01-06 12:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106120907.26701-1-marc.zyngier@arm.com>

In order to avoid aliasing attacks against the branch predictor,
some implementations require to invalidate the BTB when switching
from one user context to another.

For this, we reuse the existing implementation for Cortex-A8, and
apply it to A9, A12, A15, and A17.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/mm/proc-v7-2level.S |  4 ++--
 arch/arm/mm/proc-v7-3level.S |  6 ++++++
 arch/arm/mm/proc-v7.S        | 32 ++++++++++++++++----------------
 3 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
index c6141a5435c3..0422e58b74e8 100644
--- a/arch/arm/mm/proc-v7-2level.S
+++ b/arch/arm/mm/proc-v7-2level.S
@@ -41,7 +41,7 @@
  *	even on Cortex-A8 revisions not affected by 430973.
  *	If IBE is not set, the flush BTAC/BTB won't do anything.
  */
-ENTRY(cpu_ca8_switch_mm)
+ENTRY(cpu_v7_btbinv_switch_mm)
 #ifdef CONFIG_MMU
 	mov	r2, #0
 	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
@@ -66,7 +66,7 @@ ENTRY(cpu_v7_switch_mm)
 #endif
 	bx	lr
 ENDPROC(cpu_v7_switch_mm)
-ENDPROC(cpu_ca8_switch_mm)
+ENDPROC(cpu_v7_btbinv_switch_mm)
 
 /*
  *	cpu_v7_set_pte_ext(ptep, pte)
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 7d16bbc4102b..934272e1fa08 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -54,6 +54,11 @@
  * Set the translation table base pointer to be pgd_phys (physical address of
  * the new TTB).
  */
+ENTRY(cpu_v7_btbinv_switch_mm)
+#ifdef CONFIG_MMU
+	mov	r2, #0
+	mcr	p15, 0, r2, c7, c5, 6			@ flush BTAC/BTB
+#endif
 ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
 	mmid	r2, r2
@@ -64,6 +69,7 @@ ENTRY(cpu_v7_switch_mm)
 #endif
 	ret	lr
 ENDPROC(cpu_v7_switch_mm)
+ENDPROC(cpu_v7_btbinv_switch_mm)
 
 #ifdef __ARMEB__
 #define rl r3
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 01d64c0b2563..23fa537101ab 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -159,18 +159,18 @@ ENDPROC(cpu_v7_do_resume)
 #endif
 
 /*
- * Cortex-A8
+ * Cortex-A8/A12/A15/A17 that require a BTB invalidation on switch_mm
  */
-	globl_equ	cpu_ca8_proc_init,	cpu_v7_proc_init
-	globl_equ	cpu_ca8_proc_fin,	cpu_v7_proc_fin
-	globl_equ	cpu_ca8_reset,		cpu_v7_reset
-	globl_equ	cpu_ca8_do_idle,	cpu_v7_do_idle
-	globl_equ	cpu_ca8_dcache_clean_area, cpu_v7_dcache_clean_area
-	globl_equ	cpu_ca8_set_pte_ext,	cpu_v7_set_pte_ext
-	globl_equ	cpu_ca8_suspend_size,	cpu_v7_suspend_size
+	globl_equ	cpu_v7_btbinv_proc_init,	cpu_v7_proc_init
+	globl_equ	cpu_v7_btbinv_proc_fin,		cpu_v7_proc_fin
+	globl_equ	cpu_v7_btbinv_reset,		cpu_v7_reset
+	globl_equ	cpu_v7_btbinv_do_idle,		cpu_v7_do_idle
+	globl_equ	cpu_v7_btbinv_dcache_clean_area, cpu_v7_dcache_clean_area
+	globl_equ	cpu_v7_btbinv_set_pte_ext,	cpu_v7_set_pte_ext
+	globl_equ	cpu_v7_btbinv_suspend_size,	cpu_v7_suspend_size
 #ifdef CONFIG_ARM_CPU_SUSPEND
-	globl_equ	cpu_ca8_do_suspend,	cpu_v7_do_suspend
-	globl_equ	cpu_ca8_do_resume,	cpu_v7_do_resume
+	globl_equ	cpu_v7_btbinv_do_suspend,	cpu_v7_do_suspend
+	globl_equ	cpu_v7_btbinv_do_resume,	cpu_v7_do_resume
 #endif
 
 /*
@@ -181,7 +181,7 @@ ENDPROC(cpu_v7_do_resume)
 	globl_equ	cpu_ca9mp_reset,	cpu_v7_reset
 	globl_equ	cpu_ca9mp_do_idle,	cpu_v7_do_idle
 	globl_equ	cpu_ca9mp_dcache_clean_area, cpu_v7_dcache_clean_area
-	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_switch_mm
+	globl_equ	cpu_ca9mp_switch_mm,	cpu_v7_btbinv_switch_mm
 	globl_equ	cpu_ca9mp_set_pte_ext,	cpu_v7_set_pte_ext
 .globl	cpu_ca9mp_suspend_size
 .equ	cpu_ca9mp_suspend_size, cpu_v7_suspend_size + 4 * 2
@@ -548,8 +548,8 @@ __v7_setup_stack:
 
 	@ define struct processor (see <asm/proc-fns.h> and proc-macros.S)
 	define_processor_functions v7, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
+	define_processor_functions v7_btbinv, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
 #ifndef CONFIG_ARM_LPAE
-	define_processor_functions ca8, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
 	define_processor_functions ca9mp, dabort=v7_early_abort, pabort=v7_pabort, suspend=1
 #endif
 #ifdef CONFIG_CPU_PJ4B
@@ -614,7 +614,7 @@ __v7_ca9mp_proc_info:
 __v7_ca8_proc_info:
 	.long	0x410fc080
 	.long	0xff0ffff0
-	__v7_proc __v7_ca8_proc_info, __v7_setup, proc_fns = ca8_processor_functions
+	__v7_proc __v7_ca8_proc_info, __v7_setup, proc_fns = v7_btbinv_processor_functions
 	.size	__v7_ca8_proc_info, . - __v7_ca8_proc_info
 
 #endif	/* CONFIG_ARM_LPAE */
@@ -658,7 +658,7 @@ __v7_ca7mp_proc_info:
 __v7_ca12mp_proc_info:
 	.long	0x410fc0d0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup
+	__v7_proc __v7_ca12mp_proc_info, __v7_ca12mp_setup, proc_fns = v7_btbinv_processor_functions
 	.size	__v7_ca12mp_proc_info, . - __v7_ca12mp_proc_info
 
 	/*
@@ -668,7 +668,7 @@ __v7_ca12mp_proc_info:
 __v7_ca15mp_proc_info:
 	.long	0x410fc0f0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup
+	__v7_proc __v7_ca15mp_proc_info, __v7_ca15mp_setup, proc_fns = v7_btbinv_processor_functions
 	.size	__v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
 	/*
@@ -688,7 +688,7 @@ __v7_b15mp_proc_info:
 __v7_ca17mp_proc_info:
 	.long	0x410fc0e0
 	.long	0xff0ffff0
-	__v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup
+	__v7_proc __v7_ca17mp_proc_info, __v7_ca17mp_setup, proc_fns = v7_btbinv_processor_functions
 	.size	__v7_ca17mp_proc_info, . - __v7_ca17mp_proc_info
 
 	/*
-- 
2.14.2

^ permalink raw reply related

* [PATCH 2/3] arm: Invalidate BTB on fatal signal for Cortex A8, A9, A12, A15 and A17
From: Marc Zyngier @ 2018-01-06 12:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106120907.26701-1-marc.zyngier@arm.com>

In order to prevent aliasing attacks on the branch predictor,
invalidate the BTB on CPUs that are known to be affected.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/cp15.h |  2 ++
 arch/arm/mm/fault.c         | 11 +++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
index 4c9fa72b59f5..9e900ae855aa 100644
--- a/arch/arm/include/asm/cp15.h
+++ b/arch/arm/include/asm/cp15.h
@@ -65,6 +65,8 @@
 #define __write_sysreg(v, r, w, c, t)	asm volatile(w " " c : : "r" ((t)(v)))
 #define write_sysreg(v, ...)		__write_sysreg(v, __VA_ARGS__)
 
+#define BPIALL				__ACCESS_CP15(c7, 0, c5, 6)
+
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
 
 static inline unsigned long get_cr(void)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 42f585379e19..62da5f99eda0 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -21,6 +21,7 @@
 #include <linux/highmem.h>
 #include <linux/perf_event.h>
 
+#include <asm/cp15.h>
 #include <asm/exception.h>
 #include <asm/pgtable.h>
 #include <asm/system_misc.h>
@@ -181,6 +182,16 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
 	si.si_errno = 0;
 	si.si_code = code;
 	si.si_addr = (void __user *)addr;
+
+	switch(read_cpuid_part()) {
+	case ARM_CPU_PART_CORTEX_A8:
+	case ARM_CPU_PART_CORTEX_A9:
+	case ARM_CPU_PART_CORTEX_A12:
+	case ARM_CPU_PART_CORTEX_A15:
+	case ARM_CPU_PART_CORTEX_A17:
+		write_sysreg(0, BPIALL);
+		break;
+	}
 	force_sig_info(sig, &si, tsk);
 }
 
-- 
2.14.2

^ permalink raw reply related

* [PATCH 3/3] arm: KVM: Invalidate BTB on guest exit
From: Marc Zyngier @ 2018-01-06 12:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106120907.26701-1-marc.zyngier@arm.com>

In order to avoid aliasing attacks against the branch predictor,
let's invalidate the BTB on guest exit. This is made complicated
by the fact that we cannot take a branch before invalidating the
BTB.

Another thing is that we perform the invalidation on all
implementations, no matter if they are affected or not.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/hyp/hyp-entry.S | 74 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 63 insertions(+), 11 deletions(-)

diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
index 95a2faefc070..aa8adfa64ec9 100644
--- a/arch/arm/kvm/hyp/hyp-entry.S
+++ b/arch/arm/kvm/hyp/hyp-entry.S
@@ -61,15 +61,60 @@
 __kvm_hyp_vector:
 	.global __kvm_hyp_vector
 
-	@ Hyp-mode exception vector
-	W(b)	hyp_reset
-	W(b)	hyp_undef
-	W(b)	hyp_svc
-	W(b)	hyp_pabt
-	W(b)	hyp_dabt
-	W(b)	hyp_hvc
-	W(b)	hyp_irq
-	W(b)	hyp_fiq
+	/*
+	 * We encode the exception entry in the bottom 3 bits of
+	 * SP, and we have to guarantee to be 8 bytes aligned.
+	 */
+	add	sp, sp, #1	/* Reset 	  7 */
+	add	sp, sp, #1	/* Undef	  6 */
+	add	sp, sp, #1	/* Syscall	  5 */
+	add	sp, sp, #1	/* Prefetch abort 4 */
+	add	sp, sp, #1	/* Data abort	  3 */
+	add	sp, sp, #1	/* HVC		  2 */
+	add	sp, sp, #1	/* IRQ		  1 */
+	add	sp, sp, #1	/* FIQ		  0 */
+
+	sub	sp, sp, #1
+
+	mcr	p15, 0, r0, c7, c5, 6	/* BPIALL */
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 */
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	hyp_irq
+	b	hyp_irq
+
+1:
+	tst	sp, #2
+	bne	2f
+
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	hyp_svc
+	b	hyp_pabt
+
+2:
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	hyp_reset
+	b	hyp_undef
+
+3:
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	hyp_dabt
+	b	hyp_hvc
 
 .macro invalid_vector label, cause
 	.align
@@ -149,7 +194,14 @@ hyp_hvc:
 	bx	ip
 
 1:
-	push	{lr}
+	/*
+	 * Pushing r2 here is just a way of keeping the stack aligned to
+	 * 8 bytes on any path that can trigger a HYP exception. Here,
+	 * we may well be about to jump into the guest, and the guest
+	 * exit would otherwise be badly decoded by our fancy
+	 * "decode-exception-without-a-branch" code...
+	 */
+	push	{r2, lr}
 
 	mov	lr, r0
 	mov	r0, r1
@@ -159,7 +211,7 @@ hyp_hvc:
 THUMB(	orr	lr, #1)
 	blx	lr			@ Call the HYP function
 
-	pop	{lr}
+	pop	{r2, lr}
 	eret
 
 guest_trap:
-- 
2.14.2

^ permalink raw reply related

* [PATCH] pinctrl: imx6ul: add IOMUXC SNVS pinctrl driver for i.MX 6ULL
From: Stefan Agner @ 2018-01-06 12:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b6d157d12f87caa1ad2ab7c500aa17b2@agner.ch>

On 2018-01-06 12:14, Stefan Agner wrote:
> On 2018-01-03 09:09, Linus Walleij wrote:
>> On Tue, Jan 2, 2018 at 5:40 PM, Stefan Agner <stefan@agner.ch> wrote:
>>
>>> From: Bai Ping <ping.bai@nxp.com>
>>>
>>> On i.MX 6ULL, the BOOT_MODEx and TAMPERx pin MUX and CTRL registers
>>> are available in a separate IOMUXC_SNVS module. Add support for the
>>> IOMUXC_SNVS module to the i.MX 6UL pinctrl driver.
>>>
>>> Signed-off-by: Bai Ping <ping.bai@nxp.com>
>>> Signed-off-by: Stefan Agner <stefan@agner.ch>
>>
>> So 6 unsigned long 32 bit is succeeded by 6 unsigned long long, 64 bit?
>>
>> Someone is having fun naming these platforms I see.
> 
> Hehe, yeah definitely. At least they use proper type suffixes ;-)
> 
>>
>>>  Required properties:
>>> -- compatible: "fsl,imx6ul-iomuxc"
>>> +- compatible: "fsl,imx6ul-iomuxc" for main IOMUX controller or
>>> +  "fsl,imx6ull-iomuxc-snvs" for i.MX 6ULL's SNVS IOMUX controller.
>>
>> Pretty uncontroversial change but still nice to give the DT people a chance
>> to ACK it.
>>
>>>  static int imx6ul_pinctrl_probe(struct platform_device *pdev)
>>>  {
>>> -       return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info);
>>> +       const struct of_device_id *match;
>>> +       struct imx_pinctrl_soc_info *pinctrl_info;
>>> +
>>> +       match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
>>> +
>>> +       if (!match)
>>> +               return -ENODEV;
>>> +
>>> +       pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
>>
>> 1. Do not use a cast on void * pointers.
>>
>> 2. Use this function:
>> extern const void *of_device_get_match_data(const struct device *dev);

Just realized that imx_pinctrl_probe needs a non-const struct
imx_pinctrl_soc_info *...

Afaik, while casting to non-const struct pointers in imxXX_pinctrl_probe
is not nice but should be technically ok since it is a non-const
declaration. However, in pinmux-imx7d.c the struct imx_pinctrl_soc_info
declarations have even been constified with b3060044e495 ("pinctrl:
freescale: imx7d: make of_device_ids const"). That seems not ok!

I wonder how that even works under the light of
CONFIG_STRICT_KERNEL_RWX. In a quick test it seems to boot fine though,
as far as I can tell rodata are set to ro once boot completed...  It
seems at that point the pinmux driver has been initialized completely
and does not write to the struct anymore.

How can we fix this properly? IMHO we should at least unconstify the
struct imx7d_pinctrl_info/imx7d_lpsr_pinctrl_info declarations in
pinctrl-imx7d.c...

--
Stefan

>>
>> From <linux/of_device.h>
> 
> Ok. We use the same code in pinmux-imx7d.c, will send a patch to
> simplify that too.
> 
> --
> Stefan

^ permalink raw reply

* [PATCH] iio: adc: stm32: fix scan of multiple channels with DMA
From: Jonathan Cameron @ 2018-01-06 12:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515162894-11637-1-git-send-email-fabrice.gasnier@st.com>

On Fri, 5 Jan 2018 15:34:54 +0100
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> By default, watermark is set to '1'. Watermark is used to fine tune
> cyclic dma buffer period. In case watermark is left untouched (e.g. 1)
> and several channels are being scanned, buffer period is wrongly set
> (e.g. to 1 sample). As a consequence, data is never pushed to upper layer.
> Fix buffer period size, by taking scan channels number into account.
> 
> Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Given where we are in the cycle I've applied this to the togreg
branch for the next merge window and marked it for stable.

This is probably the quickest way to get it in at this stage.

Thanks,

Jonathan
> ---
>  drivers/iio/adc/stm32-adc.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index c9d96f9..cecf1e5 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -1315,6 +1315,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
>  {
>  	struct stm32_adc *adc = iio_priv(indio_dev);
>  	unsigned int watermark = STM32_DMA_BUFFER_SIZE / 2;
> +	unsigned int rx_buf_sz = STM32_DMA_BUFFER_SIZE;
>  
>  	/*
>  	 * dma cyclic transfers are used, buffer is split into two periods.
> @@ -1323,7 +1324,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
>  	 * - one buffer (period) driver can push with iio_trigger_poll().
>  	 */
>  	watermark = min(watermark, val * (unsigned)(sizeof(u16)));
> -	adc->rx_buf_sz = watermark * 2;
> +	adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv);
>  
>  	return 0;
>  }

^ permalink raw reply

* [PATCH v2 01/11] arm64: use RET instruction for exiting the trampoline
From: Ard Biesheuvel @ 2018-01-06 13:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515157961-20963-2-git-send-email-will.deacon@arm.com>

On 5 January 2018 at 13:12, Will Deacon <will.deacon@arm.com> wrote:
> Speculation attacks against the entry trampoline can potentially resteer
> the speculative instruction stream through the indirect branch and into
> arbitrary gadgets within the kernel.
>
> This patch defends against these attacks by forcing a misprediction
> through the return stack: a dummy BL instruction loads an entry into
> the stack, so that the predicted program flow of the subsequent RET
> instruction is to a branch-to-self instruction which is finally resolved
> as a branch to the kernel vectors with speculation suppressed.
>

How safe is it to assume that every microarchitecture will behave as
expected here? Wouldn't it be safer in general not to rely on a memory
load for x30 in the first place? (see below) Or may the speculative
execution still branch anywhere even if the branch target is
guaranteed to be known by that time?


> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm64/kernel/entry.S | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 031392ee5f47..71092ee09b6b 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -1029,6 +1029,14 @@ alternative_else_nop_endif
>         .if     \regsize == 64
>         msr     tpidrro_el0, x30        // Restored in kernel_ventry
>         .endif
> +       /*
> +        * Defend against branch aliasing attacks by pushing a dummy
> +        * entry onto the return stack and using a RET instruction to
> +        * entr the full-fat kernel vectors.
> +        */
> +       bl      2f
> +       b       .
> +2:
>         tramp_map_kernel        x30
>  #ifdef CONFIG_RANDOMIZE_BASE
>         adr     x30, tramp_vectors + PAGE_SIZE
> @@ -1041,7 +1049,7 @@ alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
>         msr     vbar_el1, x30
>         add     x30, x30, #(1b - tramp_vectors)
>         isb
> -       br      x30
> +       ret
>         .endm
>
>         .macro tramp_exit, regsize = 64
> --
> 2.1.4
>

This uses Marc's callback alternative patching for the KASLR case, the
non-KASLR case just uses a plain movz/movk sequence to load the
address of vectors rather than a literal.

(apologies for the patch soup)

diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 55d05dacd02e..e8a846335e8e 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -1031,17 +1031,19 @@ alternative_else_nop_endif
        .endif
        tramp_map_kernel        x30
 #ifdef CONFIG_RANDOMIZE_BASE
-       adr     x30, tramp_vectors + PAGE_SIZE
 alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
-       ldr     x30, [x30]
+       b       tramp_vectors + PAGE_SIZE + .Ltramp_stage2_size * (1b
- tramp_vectors - 0x400) / 0x80
 #else
-       ldr     x30, =vectors
-#endif
+       movz    x30, :abs_g3:vectors
+       movk    x30, :abs_g2_nc:vectors
+       movk    x30, :abs_g1_nc:vectors
+       movk    x30, :abs_g0_nc:vectors
        prfm    plil1strm, [x30, #(1b - tramp_vectors)]
        msr     vbar_el1, x30
        add     x30, x30, #(1b - tramp_vectors)
        isb
        br      x30
+#endif
        .endm

        .macro tramp_exit, regsize = 64
@@ -1080,12 +1082,25 @@ END(tramp_exit_compat)
        .ltorg
        .popsection                             // .entry.tramp.text
 #ifdef CONFIG_RANDOMIZE_BASE
-       .pushsection ".rodata", "a"
+       .pushsection ".text", "ax"
        .align PAGE_SHIFT
        .globl  __entry_tramp_data_start
 __entry_tramp_data_start:
-       .quad   vectors
-       .popsection                             // .rodata
+       .irpc   i, 01234567
+alternative_cb tramp_patch_vectors_address
+       movz    x30, :abs_g3:0
+       movk    x30, :abs_g2_nc:0
+       movk    x30, :abs_g1_nc:0
+       movk    x30, :abs_g0_nc:0
+alternative_cb_end
+       prfm    plil1strm, [x30, #(0x400 + \i * 0x80)]
+       msr     vbar_el1, x30
+       add     x30, x30, 0x400 + \i * 0x80
+       isb
+       br      x30
+       .endr
+       .set    .Ltramp_stage2_size, (. - __entry_tramp_data_start) / 8
+       .popsection                             // .text
 #endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 916d9ced1c3f..4a9788e76489 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -547,13 +547,38 @@ static int __init map_entry_trampoline(void)
                extern char __entry_tramp_data_start[];

                __set_fixmap(FIX_ENTRY_TRAMP_DATA,
-                            __pa_symbol(__entry_tramp_data_start),
-                            PAGE_KERNEL_RO);
+                            __pa_symbol(__entry_tramp_data_start), prot);
        }

        return 0;
 }
 core_initcall(map_entry_trampoline);
+
+#ifdef CONFIG_RANDOMIZE_BASE
+void __init tramp_patch_vectors_address(struct alt_instr *alt,
+                                       __le32 *origptr, __le32 *updptr,
+                                       int nr_inst)
+{
+       enum aarch64_insn_movewide_type type;
+       int s;
+
+       /* We only expect a 4 instruction sequence */
+       BUG_ON(nr_inst != 4);
+
+       type = AARCH64_INSN_MOVEWIDE_ZERO;
+       for (s = 0; nr_inst--; s += 16) {
+               extern const char vectors[];
+
+               u32 insn = aarch64_insn_gen_movewide(AARCH64_INSN_REG_30,
+                                                    (u16)((u64)vectors >> s),
+                                                    s,
+                                                    AARCH64_INSN_VARIANT_64BIT,
+                                                    type);
+               *updptr++ = cpu_to_le32(insn);
+               type = AARCH64_INSN_MOVEWIDE_KEEP;
+       }
+}
+#endif
 #endif

 /*

^ permalink raw reply related

* [PATCH 3/3] arm: KVM: Invalidate BTB on guest exit
From: Ard Biesheuvel @ 2018-01-06 13:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106120907.26701-4-marc.zyngier@arm.com>

On 6 January 2018 at 12:09, Marc Zyngier <marc.zyngier@arm.com> wrote:
> In order to avoid aliasing attacks against the branch predictor,
> let's invalidate the BTB on guest exit. This is made complicated
> by the fact that we cannot take a branch before invalidating the
> BTB.
>
> Another thing is that we perform the invalidation on all
> implementations, no matter if they are affected or not.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/kvm/hyp/hyp-entry.S | 74 +++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 63 insertions(+), 11 deletions(-)
>
> diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
> index 95a2faefc070..aa8adfa64ec9 100644
> --- a/arch/arm/kvm/hyp/hyp-entry.S
> +++ b/arch/arm/kvm/hyp/hyp-entry.S
> @@ -61,15 +61,60 @@
>  __kvm_hyp_vector:
>         .global __kvm_hyp_vector
>
> -       @ Hyp-mode exception vector
> -       W(b)    hyp_reset
> -       W(b)    hyp_undef
> -       W(b)    hyp_svc
> -       W(b)    hyp_pabt
> -       W(b)    hyp_dabt
> -       W(b)    hyp_hvc
> -       W(b)    hyp_irq
> -       W(b)    hyp_fiq
> +       /*
> +        * We encode the exception entry in the bottom 3 bits of
> +        * SP, and we have to guarantee to be 8 bytes aligned.
> +        */
> +       add     sp, sp, #1      /* Reset          7 */
> +       add     sp, sp, #1      /* Undef          6 */
> +       add     sp, sp, #1      /* Syscall        5 */
> +       add     sp, sp, #1      /* Prefetch abort 4 */
> +       add     sp, sp, #1      /* Data abort     3 */
> +       add     sp, sp, #1      /* HVC            2 */
> +       add     sp, sp, #1      /* IRQ            1 */
> +       add     sp, sp, #1      /* FIQ            0 */
> +
> +       sub     sp, sp, #1
> +
> +       mcr     p15, 0, r0, c7, c5, 6   /* BPIALL */
> +       isb
> +
> +       /*
> +        * As we cannot use any temporary registers and cannot
> +        * clobber SP, we can decode the exception entry using
> +        * an unrolled binary search.
> +        */
> +       tst     sp, #4
> +       bne     1f
> +
> +       tst     sp, #2
> +       bne     3f
> +
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_irq
> +       b       hyp_irq

hyp_fiq ?

> +
> +1:
> +       tst     sp, #2
> +       bne     2f
> +
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_svc
> +       b       hyp_pabt
> +
> +2:
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_reset
> +       b       hyp_undef
> +
> +3:
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_dabt
> +       b       hyp_hvc
>
>  .macro invalid_vector label, cause
>         .align
> @@ -149,7 +194,14 @@ hyp_hvc:
>         bx      ip
>
>  1:
> -       push    {lr}
> +       /*
> +        * Pushing r2 here is just a way of keeping the stack aligned to
> +        * 8 bytes on any path that can trigger a HYP exception. Here,
> +        * we may well be about to jump into the guest, and the guest
> +        * exit would otherwise be badly decoded by our fancy
> +        * "decode-exception-without-a-branch" code...
> +        */
> +       push    {r2, lr}
>
>         mov     lr, r0
>         mov     r0, r1
> @@ -159,7 +211,7 @@ hyp_hvc:
>  THUMB( orr     lr, #1)
>         blx     lr                      @ Call the HYP function
>
> -       pop     {lr}
> +       pop     {r2, lr}
>         eret
>
>  guest_trap:
> --
> 2.14.2
>
>
> _______________________________________________
> 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 3/3] arm: KVM: Invalidate BTB on guest exit
From: Ard Biesheuvel @ 2018-01-06 13:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106120907.26701-4-marc.zyngier@arm.com>

On 6 January 2018 at 12:09, Marc Zyngier <marc.zyngier@arm.com> wrote:
> In order to avoid aliasing attacks against the branch predictor,
> let's invalidate the BTB on guest exit. This is made complicated
> by the fact that we cannot take a branch before invalidating the
> BTB.
>

You can't even take an unconditional branch?

> Another thing is that we perform the invalidation on all
> implementations, no matter if they are affected or not.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/kvm/hyp/hyp-entry.S | 74 +++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 63 insertions(+), 11 deletions(-)
>
> diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
> index 95a2faefc070..aa8adfa64ec9 100644
> --- a/arch/arm/kvm/hyp/hyp-entry.S
> +++ b/arch/arm/kvm/hyp/hyp-entry.S
> @@ -61,15 +61,60 @@
>  __kvm_hyp_vector:
>         .global __kvm_hyp_vector
>
> -       @ Hyp-mode exception vector
> -       W(b)    hyp_reset
> -       W(b)    hyp_undef
> -       W(b)    hyp_svc
> -       W(b)    hyp_pabt
> -       W(b)    hyp_dabt
> -       W(b)    hyp_hvc
> -       W(b)    hyp_irq
> -       W(b)    hyp_fiq
> +       /*
> +        * We encode the exception entry in the bottom 3 bits of
> +        * SP, and we have to guarantee to be 8 bytes aligned.
> +        */
> +       add     sp, sp, #1      /* Reset          7 */
> +       add     sp, sp, #1      /* Undef          6 */
> +       add     sp, sp, #1      /* Syscall        5 */
> +       add     sp, sp, #1      /* Prefetch abort 4 */
> +       add     sp, sp, #1      /* Data abort     3 */
> +       add     sp, sp, #1      /* HVC            2 */
> +       add     sp, sp, #1      /* IRQ            1 */
> +       add     sp, sp, #1      /* FIQ            0 */
> +
> +       sub     sp, sp, #1
> +
> +       mcr     p15, 0, r0, c7, c5, 6   /* BPIALL */
> +       isb
> +
> +       /*
> +        * As we cannot use any temporary registers and cannot
> +        * clobber SP, we can decode the exception entry using
> +        * an unrolled binary search.
> +        */
> +       tst     sp, #4
> +       bne     1f
> +
> +       tst     sp, #2
> +       bne     3f
> +
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_irq
> +       b       hyp_irq
> +
> +1:
> +       tst     sp, #2
> +       bne     2f
> +
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_svc
> +       b       hyp_pabt
> +
> +2:
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_reset
> +       b       hyp_undef
> +
> +3:
> +       tst     sp, #1
> +       bic     sp, sp, #0x7
> +       bne     hyp_dabt
> +       b       hyp_hvc
>
>  .macro invalid_vector label, cause
>         .align
> @@ -149,7 +194,14 @@ hyp_hvc:
>         bx      ip
>
>  1:
> -       push    {lr}
> +       /*
> +        * Pushing r2 here is just a way of keeping the stack aligned to
> +        * 8 bytes on any path that can trigger a HYP exception. Here,
> +        * we may well be about to jump into the guest, and the guest
> +        * exit would otherwise be badly decoded by our fancy
> +        * "decode-exception-without-a-branch" code...
> +        */
> +       push    {r2, lr}
>
>         mov     lr, r0
>         mov     r0, r1
> @@ -159,7 +211,7 @@ hyp_hvc:
>  THUMB( orr     lr, #1)
>         blx     lr                      @ Call the HYP function
>
> -       pop     {lr}
> +       pop     {r2, lr}
>         eret
>
>  guest_trap:
> --
> 2.14.2
>
>
> _______________________________________________
> 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 3/3] arm: KVM: Invalidate BTB on guest exit
From: Marc Zyngier @ 2018-01-06 13:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu-1JRts29L29CyMJ2Mba0aaVTS2W1yGRKqOyT1XTEmdUQ@mail.gmail.com>

On Sat, 6 Jan 2018 13:27:13 +0000
Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:

> On 6 January 2018 at 12:09, Marc Zyngier <marc.zyngier@arm.com> wrote:
> > In order to avoid aliasing attacks against the branch predictor,
> > let's invalidate the BTB on guest exit. This is made complicated
> > by the fact that we cannot take a branch before invalidating the
> > BTB.
> >
> > Another thing is that we perform the invalidation on all
> > implementations, no matter if they are affected or not.
> >
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  arch/arm/kvm/hyp/hyp-entry.S | 74 +++++++++++++++++++++++++++++++++++++-------
> >  1 file changed, 63 insertions(+), 11 deletions(-)
> >
> > diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
> > index 95a2faefc070..aa8adfa64ec9 100644
> > --- a/arch/arm/kvm/hyp/hyp-entry.S
> > +++ b/arch/arm/kvm/hyp/hyp-entry.S
> > @@ -61,15 +61,60 @@
> >  __kvm_hyp_vector:
> >         .global __kvm_hyp_vector
> >
> > -       @ Hyp-mode exception vector
> > -       W(b)    hyp_reset
> > -       W(b)    hyp_undef
> > -       W(b)    hyp_svc
> > -       W(b)    hyp_pabt
> > -       W(b)    hyp_dabt
> > -       W(b)    hyp_hvc
> > -       W(b)    hyp_irq
> > -       W(b)    hyp_fiq
> > +       /*
> > +        * We encode the exception entry in the bottom 3 bits of
> > +        * SP, and we have to guarantee to be 8 bytes aligned.
> > +        */
> > +       add     sp, sp, #1      /* Reset          7 */
> > +       add     sp, sp, #1      /* Undef          6 */
> > +       add     sp, sp, #1      /* Syscall        5 */
> > +       add     sp, sp, #1      /* Prefetch abort 4 */
> > +       add     sp, sp, #1      /* Data abort     3 */
> > +       add     sp, sp, #1      /* HVC            2 */
> > +       add     sp, sp, #1      /* IRQ            1 */
> > +       add     sp, sp, #1      /* FIQ            0 */
> > +
> > +       sub     sp, sp, #1
> > +
> > +       mcr     p15, 0, r0, c7, c5, 6   /* BPIALL */
> > +       isb
> > +
> > +       /*
> > +        * As we cannot use any temporary registers and cannot
> > +        * clobber SP, we can decode the exception entry using
> > +        * an unrolled binary search.
> > +        */
> > +       tst     sp, #4
> > +       bne     1f
> > +
> > +       tst     sp, #2
> > +       bne     3f
> > +
> > +       tst     sp, #1
> > +       bic     sp, sp, #0x7
> > +       bne     hyp_irq
> > +       b       hyp_irq  
> 
> hyp_fiq ?

Indeed. Thanks for spotting that one!

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* [PATCH 3/3] arm: KVM: Invalidate BTB on guest exit
From: Marc Zyngier @ 2018-01-06 13:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu8JjwtoWUiY9zyhukarAfXB-LQHb10gb7tSE0iJ308b7w@mail.gmail.com>

On Sat, 6 Jan 2018 13:35:46 +0000
Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:

> On 6 January 2018 at 12:09, Marc Zyngier <marc.zyngier@arm.com> wrote:
> > In order to avoid aliasing attacks against the branch predictor,
> > let's invalidate the BTB on guest exit. This is made complicated
> > by the fact that we cannot take a branch before invalidating the
> > BTB.
> >  
> 
> You can't even take an unconditional branch?

Yup.  We certainly have that restriction on arm64, and I assume it is
the same on 32bit.

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* [PATCH 2/5] clk: lpc32xx: read-only divider can propagate rate change
From: Vladimir Zapolskiy @ 2018-01-06 14:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515181225.5048.52.camel@baylibre.com>

Hi Jerome,

On 01/05/2018 09:40 PM, Jerome Brunet wrote:
> On Fri, 2018-01-05 at 20:12 +0200, Vladimir Zapolskiy wrote:
>> Hi Jerome,
>>
>> On 01/05/2018 07:09 PM, Jerome Brunet wrote:
>>> When a divider clock has CLK_DIVIDER_READ_ONLY set, it means that the
>>> register shall be left un-touched, but it does not mean the clock
>>> should stop rate propagation if CLK_SET_RATE_PARENT is set
>>>
>>
>> okay, the statement sounds correct, but there is no such clocks on LPC32xx,
>> thus I hardly can confirm that adding dead/inapplicable code is a fix.
>>
>>> This properly handled in qcom clk-regmap-divider but it was not in the
>>> lpc32xx divider
>>>
>>> Fixes: f7c82a60ba26 ("clk: lpc32xx: add common clock framework driver")
>>> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
>>
>> I would suggest to drop two LPC32xx clock driver changes from the series.
> 
> Hi Vladimir,
> 
> This is fine by me. Whether LPC32xx supports CLK_DIVIDER_READ_ONLY is up to you,
> but you should be consistent about it.
> 
> I added the fix to LPC32xx because it looks like the generic divider (a lot) and

right, the relevant divider operations were copied, however the difference
is important, unfortunately there is no simple option to get rid of regmap,
because System Control Block registers are shared with a number of other
device drivers.

> appears to support CLK_DIVIDER_READ_ONLY. If it does not, could you please kill
> the related code ?

The driver supports CLK_DIVIDER_READ_ONLY clocks, and it should not be
changed, but all such clocks don't have children with CLK_SET_RATE_PARENT
property, which invalidates your fix for LPC32xx. Please let me know,
if I missed something.

--
With best wishes,
Vladimir

^ permalink raw reply

* [PATCH v2 0/5] constify struct imx_pinctrl_soc_info
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset grew out of the discussion around the first version
of "pinctrl: imx6ul: add IOMUXC SNVS pinctrl driver for i.MX 6ULL".
This is necessary for pinctrls of SoCs with multiple compatible
strings (currently only imx7d) since the struct uses the .data
pointer in struct of_device_id. It is also helpful for all other
SoCs since it decreases the .data section for all drivers by 1276
bytes.

Bai Ping (1):
  pinctrl: imx6ul: add IOMUXC SNVS pinctrl driver for i.MX 6ULL

Stefan Agner (4):
  pinctrl: imx: use struct imx_pinctrl_soc_info as a const
  pinctrl: imx7d: simplify imx7d_pinctrl_probe
  pinctrl: imx: constify struct imx_pinctrl_soc_info
  pinctrl: imx7ulp: constify struct imx_cfg_params_decode

 .../bindings/pinctrl/fsl,imx6ul-pinctrl.txt        |  3 +-
 drivers/pinctrl/freescale/pinctrl-imx.c            | 81 ++++++++++------------
 drivers/pinctrl/freescale/pinctrl-imx.h            | 13 ++--
 drivers/pinctrl/freescale/pinctrl-imx25.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx35.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx50.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx51.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx53.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx6dl.c         |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx6q.c          |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx6sl.c         |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx6sx.c         |  2 +-
 drivers/pinctrl/freescale/pinctrl-imx6ul.c         | 52 ++++++++++++--
 drivers/pinctrl/freescale/pinctrl-imx7d.c          | 10 +--
 drivers/pinctrl/freescale/pinctrl-imx7ulp.c        |  7 +-
 drivers/pinctrl/freescale/pinctrl-vf610.c          |  5 +-
 16 files changed, 111 insertions(+), 78 deletions(-)

-- 
2.15.1

^ permalink raw reply

* [PATCH v2 1/5] pinctrl: imx: use struct imx_pinctrl_soc_info as a const
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106142553.15322-1-stefan@agner.ch>

For some SoCs the struct imx_pinctrl_soc_info is passed through
of_device_id.data which is const. Most variables are already const
or otherwise not written. However, some fields are modified at
runtime. Move those fields to the dynamically allocated struct
imx_pinctrl.

Fixes: b3060044e495 ("pinctrl: freescale: imx7d: make of_device_ids const")
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Arvind Yadav <arvind.yadav.cs@gmail.com>
Cc: Dong Aisheng <aisheng.dong@nxp.com>
Cc: Gary Bisson <gary.bisson@boundarydevices.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/pinctrl/freescale/pinctrl-imx.c     | 79 ++++++++++++++---------------
 drivers/pinctrl/freescale/pinctrl-imx.h     | 11 ++--
 drivers/pinctrl/freescale/pinctrl-imx7ulp.c |  3 +-
 drivers/pinctrl/freescale/pinctrl-vf610.c   |  3 +-
 4 files changed, 44 insertions(+), 52 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 6e472691d8ee..86256d25c4a3 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -62,7 +62,6 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 			struct pinctrl_map **map, unsigned *num_maps)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct group_desc *grp;
 	struct pinctrl_map *new_map;
 	struct device_node *parent;
@@ -75,7 +74,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
 	 */
 	grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
 	if (!grp) {
-		dev_err(info->dev, "unable to find group for node %s\n",
+		dev_err(ipctl->dev, "unable to find group for node %s\n",
 			np->name);
 		return -EINVAL;
 	}
@@ -146,7 +145,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
 		       unsigned group)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg;
 	unsigned int npins, pin_id;
 	int i;
@@ -174,7 +173,7 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
 		struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
 
 		pin_id = pin->pin;
-		pin_reg = &info->pin_regs[pin_id];
+		pin_reg = &ipctl->pin_regs[pin_id];
 
 		if (pin_reg->mux_reg == -1) {
 			dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
@@ -255,7 +254,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl,
 					      unsigned long *configs,
 					      unsigned int num_configs)
 {
-	struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	struct imx_cfg_params_decode *decode;
 	enum pin_config_param param;
 	u32 raw_config = 0;
@@ -289,7 +288,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl,
 static u32 imx_pinconf_parse_generic_config(struct device_node *np,
 					    struct imx_pinctrl *ipctl)
 {
-	struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	struct pinctrl_dev *pctl = ipctl->pctl;
 	unsigned int num_configs;
 	unsigned long *configs;
@@ -310,11 +309,11 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
 			     unsigned pin_id, unsigned long *config)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
 
 	if (pin_reg->conf_reg == -1) {
-		dev_err(info->dev, "Pin(%s) does not support config function\n",
+		dev_err(ipctl->dev, "Pin(%s) does not support config function\n",
 			info->pins[pin_id].name);
 		return -EINVAL;
 	}
@@ -332,12 +331,12 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
 			     unsigned num_configs)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
 	int i;
 
 	if (pin_reg->conf_reg == -1) {
-		dev_err(info->dev, "Pin(%s) does not support config function\n",
+		dev_err(ipctl->dev, "Pin(%s) does not support config function\n",
 			info->pins[pin_id].name);
 		return -EINVAL;
 	}
@@ -368,8 +367,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
 				   struct seq_file *s, unsigned pin_id)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
-	const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+	const struct imx_pin_reg *pin_reg = &ipctl->pin_regs[pin_id];
 	unsigned long config;
 
 	if (!pin_reg || pin_reg->conf_reg == -1) {
@@ -427,13 +425,13 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 				    struct imx_pinctrl *ipctl,
 				    u32 index)
 {
-	struct imx_pinctrl_soc_info *info = ipctl->info;
+	const struct imx_pinctrl_soc_info *info = ipctl->info;
 	int size, pin_size;
 	const __be32 *list;
 	int i;
 	u32 config;
 
-	dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+	dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name);
 
 	if (info->flags & SHARE_MUX_CONF_REG)
 		pin_size = SHARE_FSL_PIN_SIZE;
@@ -460,7 +458,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 	if (!list) {
 		list = of_get_property(np, "pinmux", &size);
 		if (!list) {
-			dev_err(info->dev,
+			dev_err(ipctl->dev,
 				"no fsl,pins and pins property in node %pOF\n", np);
 			return -EINVAL;
 		}
@@ -468,7 +466,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 
 	/* we do not check return since it's safe node passed down */
 	if (!size || size % pin_size) {
-		dev_err(info->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
+		dev_err(ipctl->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
 		return -EINVAL;
 	}
 
@@ -476,9 +474,9 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 	config = imx_pinconf_parse_generic_config(np, ipctl);
 
 	grp->num_pins = size / pin_size;
-	grp->data = devm_kzalloc(info->dev, grp->num_pins *
+	grp->data = devm_kzalloc(ipctl->dev, grp->num_pins *
 				 sizeof(struct imx_pin), GFP_KERNEL);
-	grp->pins = devm_kzalloc(info->dev, grp->num_pins *
+	grp->pins = devm_kzalloc(ipctl->dev, grp->num_pins *
 				 sizeof(unsigned int), GFP_KERNEL);
 	if (!grp->pins || !grp->data)
 		return -ENOMEM;
@@ -502,7 +500,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 		}
 
 		pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
-		pin_reg = &info->pin_regs[pin_id];
+		pin_reg = &ipctl->pin_regs[pin_id];
 		pin->pin = pin_id;
 		grp->pins[i] = pin_id;
 		pin_reg->mux_reg = mux_reg;
@@ -524,7 +522,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
 			pin->config = config & ~IMX_PAD_SION;
 		}
 
-		dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
+		dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
 				pin->mux_mode, pin->config);
 	}
 
@@ -536,13 +534,12 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
 				       u32 index)
 {
 	struct pinctrl_dev *pctl = ipctl->pctl;
-	struct imx_pinctrl_soc_info *info = ipctl->info;
 	struct device_node *child;
 	struct function_desc *func;
 	struct group_desc *grp;
 	u32 i = 0;
 
-	dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+	dev_dbg(pctl->dev, "parse function(%d): %s\n", index, np->name);
 
 	func = pinmux_generic_get_function(pctl, index);
 	if (!func)
@@ -552,10 +549,10 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
 	func->name = np->name;
 	func->num_group_names = of_get_child_count(np);
 	if (func->num_group_names == 0) {
-		dev_err(info->dev, "no groups defined in %pOF\n", np);
+		dev_err(ipctl->dev, "no groups defined in %pOF\n", np);
 		return -EINVAL;
 	}
-	func->group_names = devm_kcalloc(info->dev, func->num_group_names,
+	func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names,
 					 sizeof(char *), GFP_KERNEL);
 	if (!func->group_names)
 		return -ENOMEM;
@@ -563,15 +560,15 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
 	for_each_child_of_node(np, child) {
 		func->group_names[i] = child->name;
 
-		grp = devm_kzalloc(info->dev, sizeof(struct group_desc),
+		grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
 				   GFP_KERNEL);
 		if (!grp)
 			return -ENOMEM;
 
-		mutex_lock(&info->mutex);
+		mutex_lock(&ipctl->mutex);
 		radix_tree_insert(&pctl->pin_group_tree,
-				  info->group_index++, grp);
-		mutex_unlock(&info->mutex);
+				  ipctl->group_index++, grp);
+		mutex_unlock(&ipctl->mutex);
 
 		imx_pinctrl_parse_groups(child, grp, ipctl, i++);
 	}
@@ -608,7 +605,6 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *child;
 	struct pinctrl_dev *pctl = ipctl->pctl;
-	struct imx_pinctrl_soc_info *info = ipctl->info;
 	u32 nfuncs = 0;
 	u32 i = 0;
 	bool flat_funcs;
@@ -635,13 +631,13 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
 		if (!function)
 			return -ENOMEM;
 
-		mutex_lock(&info->mutex);
+		mutex_lock(&ipctl->mutex);
 		radix_tree_insert(&pctl->pin_function_tree, i, function);
-		mutex_unlock(&info->mutex);
+		mutex_unlock(&ipctl->mutex);
 	}
 	pctl->num_functions = nfuncs;
 
-	info->group_index = 0;
+	ipctl->group_index = 0;
 	if (flat_funcs) {
 		pctl->num_groups = of_get_child_count(np);
 	} else {
@@ -672,7 +668,7 @@ static void imx_free_resources(struct imx_pinctrl *ipctl)
 }
 
 int imx_pinctrl_probe(struct platform_device *pdev,
-		      struct imx_pinctrl_soc_info *info)
+		      const struct imx_pinctrl_soc_info *info)
 {
 	struct regmap_config config = { .name = "gpr" };
 	struct device_node *dev_np = pdev->dev.of_node;
@@ -687,7 +683,6 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 		dev_err(&pdev->dev, "wrong pinctrl info\n");
 		return -EINVAL;
 	}
-	info->dev = &pdev->dev;
 
 	if (info->gpr_compatible) {
 		gpr = syscon_regmap_lookup_by_compatible(info->gpr_compatible);
@@ -700,14 +695,14 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 	if (!ipctl)
 		return -ENOMEM;
 
-	info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
+	ipctl->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*ipctl->pin_regs) *
 				      info->npins, GFP_KERNEL);
-	if (!info->pin_regs)
+	if (!ipctl->pin_regs)
 		return -ENOMEM;
 
 	for (i = 0; i < info->npins; i++) {
-		info->pin_regs[i].mux_reg = -1;
-		info->pin_regs[i].conf_reg = -1;
+		ipctl->pin_regs[i].mux_reg = -1;
+		ipctl->pin_regs[i].conf_reg = -1;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -751,10 +746,10 @@ int imx_pinctrl_probe(struct platform_device *pdev,
 	/* platform specific callback */
 	imx_pmx_ops.gpio_set_direction = info->gpio_set_direction;
 
-	mutex_init(&info->mutex);
+	mutex_init(&ipctl->mutex);
 
 	ipctl->info = info;
-	ipctl->dev = info->dev;
+	ipctl->dev = &pdev->dev;
 	platform_set_drvdata(pdev, ipctl);
 	ret = devm_pinctrl_register_and_init(&pdev->dev,
 					     imx_pinctrl_desc, ipctl,
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h
index 5aa22b52c1d4..41ee75537da4 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.h
+++ b/drivers/pinctrl/freescale/pinctrl-imx.h
@@ -58,14 +58,10 @@ struct imx_cfg_params_decode {
 };
 
 struct imx_pinctrl_soc_info {
-	struct device *dev;
 	const struct pinctrl_pin_desc *pins;
 	unsigned int npins;
-	struct imx_pin_reg *pin_regs;
-	unsigned int group_index;
 	unsigned int flags;
 	const char *gpr_compatible;
-	struct mutex mutex;
 
 	/* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */
 	unsigned int mux_mask;
@@ -95,7 +91,10 @@ struct imx_pinctrl {
 	struct pinctrl_dev *pctl;
 	void __iomem *base;
 	void __iomem *input_sel_base;
-	struct imx_pinctrl_soc_info *info;
+	const struct imx_pinctrl_soc_info *info;
+	struct imx_pin_reg *pin_regs;
+	unsigned int group_index;
+	struct mutex mutex;
 };
 
 #define IMX_CFG_PARAMS_DECODE(p, m, o) \
@@ -117,5 +116,5 @@ struct imx_pinctrl {
 #define IOMUXC_CONFIG_SION	(0x1 << 4)
 
 int imx_pinctrl_probe(struct platform_device *pdev,
-			struct imx_pinctrl_soc_info *info);
+			const struct imx_pinctrl_soc_info *info);
 #endif /* __DRIVERS_PINCTRL_IMX_H */
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
index b7bebb292f37..9161c984f57b 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
@@ -307,11 +307,10 @@ static int imx7ulp_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 					  unsigned offset, bool input)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg;
 	u32 reg;
 
-	pin_reg = &info->pin_regs[offset];
+	pin_reg = &ipctl->pin_regs[offset];
 	if (pin_reg->mux_reg == -1)
 		return -EINVAL;
 
diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c
index ac18bb6d6d5e..42745c690be3 100644
--- a/drivers/pinctrl/freescale/pinctrl-vf610.c
+++ b/drivers/pinctrl/freescale/pinctrl-vf610.c
@@ -300,11 +300,10 @@ static int vf610_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 					unsigned offset, bool input)
 {
 	struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
-	struct imx_pinctrl_soc_info *info = ipctl->info;
 	const struct imx_pin_reg *pin_reg;
 	u32 reg;
 
-	pin_reg = &info->pin_regs[offset];
+	pin_reg = &ipctl->pin_regs[offset];
 	if (pin_reg->mux_reg == -1)
 		return -EINVAL;
 
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 2/5] pinctrl: imx7d: simplify imx7d_pinctrl_probe
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106142553.15322-1-stefan@agner.ch>

Using of_device_get_match_data in imx7d_pinctrl_probe simplifies
the function. Also get rid of the void pointer cast since
imx_pinctrl_probe now accepts const struct imx_pinctrl_soc_info.

Cc: Arvind Yadav <arvind.yadav.cs@gmail.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/pinctrl/freescale/pinctrl-imx7d.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c
index 754159ee7b1e..0b0a2f33b06a 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7d.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c
@@ -378,16 +378,12 @@ static const struct of_device_id imx7d_pinctrl_of_match[] = {
 
 static int imx7d_pinctrl_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *match;
-	struct imx_pinctrl_soc_info *pinctrl_info;
+	const struct imx_pinctrl_soc_info *pinctrl_info;
 
-	match = of_match_device(imx7d_pinctrl_of_match, &pdev->dev);
-
-	if (!match)
+	pinctrl_info = of_device_get_match_data(&pdev->dev);
+	if (!pinctrl_info)
 		return -ENODEV;
 
-	pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
-
 	return imx_pinctrl_probe(pdev, pinctrl_info);
 }
 
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 3/5] pinctrl: imx: constify struct imx_pinctrl_soc_info
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106142553.15322-1-stefan@agner.ch>

Now that imx_pinctrl_probe accepts const struct imx_pinctrl_soc_info
we can constify all declarations of struct imx_pinctrl_soc_info.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/pinctrl/freescale/pinctrl-imx25.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx35.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx50.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx51.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx53.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx6dl.c  | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx6q.c   | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx6sl.c  | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx6sx.c  | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx7ulp.c | 2 +-
 drivers/pinctrl/freescale/pinctrl-vf610.c   | 2 +-
 11 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c
index d7367fabe712..db6d9d1382f9 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx25.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx25.c
@@ -309,7 +309,7 @@ static const struct pinctrl_pin_desc imx25_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX25_PAD_BOOT_MODE1),
 };
 
-static struct imx_pinctrl_soc_info imx25_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx25_pinctrl_info = {
 	.pins = imx25_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx25_pinctrl_pads),
 };
diff --git a/drivers/pinctrl/freescale/pinctrl-imx35.c b/drivers/pinctrl/freescale/pinctrl-imx35.c
index 6315ba6af431..6927946ae4b5 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx35.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx35.c
@@ -999,7 +999,7 @@ static const struct pinctrl_pin_desc imx35_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX35_PAD_TEST_MODE),
 };
 
-static struct imx_pinctrl_soc_info imx35_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx35_pinctrl_info = {
 	.pins = imx35_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx35_pinctrl_pads),
 };
diff --git a/drivers/pinctrl/freescale/pinctrl-imx50.c b/drivers/pinctrl/freescale/pinctrl-imx50.c
index 8e3a17df5c5d..eb349b97290f 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx50.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx50.c
@@ -385,7 +385,7 @@ static const struct pinctrl_pin_desc imx50_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX50_PAD_EIM_CRE),
 };
 
-static struct imx_pinctrl_soc_info imx50_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx50_pinctrl_info = {
 	.pins = imx50_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx50_pinctrl_pads),
 	.gpr_compatible = "fsl,imx50-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx51.c b/drivers/pinctrl/freescale/pinctrl-imx51.c
index eeac64ba2709..49acd991b5fb 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx51.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx51.c
@@ -762,7 +762,7 @@ static const struct pinctrl_pin_desc imx51_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX51_PAD_CSI1_MCLK),
 };
 
-static struct imx_pinctrl_soc_info imx51_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx51_pinctrl_info = {
 	.pins = imx51_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx51_pinctrl_pads),
 };
diff --git a/drivers/pinctrl/freescale/pinctrl-imx53.c b/drivers/pinctrl/freescale/pinctrl-imx53.c
index 46a9572f3473..6dd0c60eaea4 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx53.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx53.c
@@ -448,7 +448,7 @@ static const struct pinctrl_pin_desc imx53_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX53_PAD_GPIO_18),
 };
 
-static struct imx_pinctrl_soc_info imx53_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx53_pinctrl_info = {
 	.pins = imx53_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx53_pinctrl_pads),
 	.gpr_compatible = "fsl,imx53-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6dl.c b/drivers/pinctrl/freescale/pinctrl-imx6dl.c
index 3f25ca5867cc..91b85fc01de8 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6dl.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6dl.c
@@ -457,7 +457,7 @@ static const struct pinctrl_pin_desc imx6dl_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6DL_PAD_SD4_DAT7),
 };
 
-static struct imx_pinctrl_soc_info imx6dl_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx6dl_pinctrl_info = {
 	.pins = imx6dl_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx6dl_pinctrl_pads),
 	.gpr_compatible = "fsl,imx6q-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6q.c b/drivers/pinctrl/freescale/pinctrl-imx6q.c
index d61651c40458..5f653d69d0f5 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6q.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6q.c
@@ -460,7 +460,7 @@ static const struct pinctrl_pin_desc imx6q_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6Q_PAD_SD2_DAT3),
 };
 
-static struct imx_pinctrl_soc_info imx6q_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx6q_pinctrl_info = {
 	.pins = imx6q_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx6q_pinctrl_pads),
 	.gpr_compatible = "fsl,imx6q-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sl.c b/drivers/pinctrl/freescale/pinctrl-imx6sl.c
index d023f6b00623..1167dc273c04 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6sl.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6sl.c
@@ -363,7 +363,7 @@ static const struct pinctrl_pin_desc imx6sl_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6SL_PAD_WDOG_B),
 };
 
-static struct imx_pinctrl_soc_info imx6sl_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx6sl_pinctrl_info = {
 	.pins = imx6sl_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx6sl_pinctrl_pads),
 	.gpr_compatible = "fsl,imx6sl-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sx.c b/drivers/pinctrl/freescale/pinctrl-imx6sx.c
index 898b781701e6..15ea56c75f68 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6sx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6sx.c
@@ -367,7 +367,7 @@ static const struct pinctrl_pin_desc imx6sx_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6SX_PAD_USB_H_STROBE),
 };
 
-static struct imx_pinctrl_soc_info imx6sx_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx6sx_pinctrl_info = {
 	.pins = imx6sx_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx6sx_pinctrl_pads),
 	.gpr_compatible = "fsl,imx6sx-iomuxc-gpr",
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
index 9161c984f57b..0406d8b39e6a 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
@@ -324,7 +324,7 @@ static int imx7ulp_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 	return 0;
 }
 
-static struct imx_pinctrl_soc_info imx7ulp_pinctrl_info = {
+static const struct imx_pinctrl_soc_info imx7ulp_pinctrl_info = {
 	.pins = imx7ulp_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx7ulp_pinctrl_pads),
 	.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG,
diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c
index 42745c690be3..c078f859ae15 100644
--- a/drivers/pinctrl/freescale/pinctrl-vf610.c
+++ b/drivers/pinctrl/freescale/pinctrl-vf610.c
@@ -318,7 +318,7 @@ static int vf610_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 	return 0;
 }
 
-static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
+static const struct imx_pinctrl_soc_info vf610_pinctrl_info = {
 	.pins = vf610_pinctrl_pads,
 	.npins = ARRAY_SIZE(vf610_pinctrl_pads),
 	.flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID,
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 4/5] pinctrl: imx7ulp: constify struct imx_cfg_params_decode
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106142553.15322-1-stefan@agner.ch>

The decode parameters are constant mark them const.

Cc: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/pinctrl/freescale/pinctrl-imx.c     | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx.h     | 2 +-
 drivers/pinctrl/freescale/pinctrl-imx7ulp.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 86256d25c4a3..24aaddd760a0 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -255,7 +255,7 @@ static u32 imx_pinconf_decode_generic_config(struct imx_pinctrl *ipctl,
 					      unsigned int num_configs)
 {
 	const struct imx_pinctrl_soc_info *info = ipctl->info;
-	struct imx_cfg_params_decode *decode;
+	const struct imx_cfg_params_decode *decode;
 	enum pin_config_param param;
 	u32 raw_config = 0;
 	u32 param_val;
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h
index 41ee75537da4..038e8c0e5b96 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.h
+++ b/drivers/pinctrl/freescale/pinctrl-imx.h
@@ -71,7 +71,7 @@ struct imx_pinctrl_soc_info {
 	bool generic_pinconf;
 	const struct pinconf_generic_params *custom_params;
 	unsigned int num_custom_params;
-	struct imx_cfg_params_decode *decodes;
+	const struct imx_cfg_params_decode *decodes;
 	unsigned int num_decodes;
 	void (*fixup)(unsigned long *configs, unsigned int num_configs,
 		      u32 *raw_config);
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
index 0406d8b39e6a..f363e45fd246 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
@@ -266,7 +266,7 @@ static const struct pinctrl_pin_desc imx7ulp_pinctrl_pads[] = {
 #define BP_MUX_MODE		8
 #define BM_PULL_ENABLED		BIT(1)
 
-struct imx_cfg_params_decode imx7ulp_cfg_decodes[] = {
+static const struct imx_cfg_params_decode imx7ulp_cfg_decodes[] = {
 	IMX_CFG_PARAMS_DECODE(PIN_CONFIG_DRIVE_STRENGTH, 		BIT(6), 6),
 	IMX_CFG_PARAMS_DECODE(PIN_CONFIG_DRIVE_PUSH_PULL,		BIT(5), 5),
 	IMX_CFG_PARAMS_DECODE(PIN_CONFIG_SLEW_RATE,			BIT(2), 2),
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 5/5] pinctrl: imx6ul: add IOMUXC SNVS pinctrl driver for i.MX 6ULL
From: Stefan Agner @ 2018-01-06 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180106142553.15322-1-stefan@agner.ch>

From: Bai Ping <ping.bai@nxp.com>

On i.MX 6ULL, the BOOT_MODEx and TAMPERx pin MUX and CTRL registers
are available in a separate IOMUXC_SNVS module. Add support for the
IOMUXC_SNVS module to the i.MX 6UL pinctrl driver.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../bindings/pinctrl/fsl,imx6ul-pinctrl.txt        |  3 +-
 drivers/pinctrl/freescale/pinctrl-imx6ul.c         | 52 ++++++++++++++++++++--
 2 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt
index a81bbf37ed66..7ca4f6118d9a 100644
--- a/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt
@@ -4,7 +4,8 @@ Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
 and usage.
 
 Required properties:
-- compatible: "fsl,imx6ul-iomuxc"
+- compatible: "fsl,imx6ul-iomuxc" for main IOMUX controller or
+  "fsl,imx6ull-iomuxc-snvs" for i.MX 6ULL's SNVS IOMUX controller.
 - fsl,pins: each entry consists of 6 integers and represents the mux and config
   setting for one pin.  The first 5 integers <mux_reg conf_reg input_reg mux_val
   input_val> are specified using a PIN_FUNC_ID macro, which can be found in
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
index 1aeb840aae1d..4580717ade19 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6ul.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
@@ -150,6 +150,21 @@ enum imx6ul_pads {
 	MX6UL_PAD_CSI_DATA07 = 128,
 };
 
+enum imx6ull_lpsr_pads {
+	MX6ULL_PAD_BOOT_MODE0 = 0,
+	MX6ULL_PAD_BOOT_MODE1 = 1,
+	MX6ULL_PAD_SNVS_TAMPER0 = 2,
+	MX6ULL_PAD_SNVS_TAMPER1 = 3,
+	MX6ULL_PAD_SNVS_TAMPER2 = 4,
+	MX6ULL_PAD_SNVS_TAMPER3 = 5,
+	MX6ULL_PAD_SNVS_TAMPER4 = 6,
+	MX6ULL_PAD_SNVS_TAMPER5 = 7,
+	MX6ULL_PAD_SNVS_TAMPER6 = 8,
+	MX6ULL_PAD_SNVS_TAMPER7 = 9,
+	MX6ULL_PAD_SNVS_TAMPER8 = 10,
+	MX6ULL_PAD_SNVS_TAMPER9 = 11,
+};
+
 /* Pad names for the pinmux subsystem */
 static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0),
@@ -283,20 +298,49 @@ static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
 	IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07),
 };
 
-static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
+/* pad for i.MX6ULL lpsr pinmux */
+static const struct pinctrl_pin_desc imx6ull_snvs_pinctrl_pads[] = {
+	IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE0),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE1),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER0),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER1),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER2),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER3),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER4),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER5),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER6),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER7),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER8),
+	IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER9),
+};
+
+static const struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
 	.pins = imx6ul_pinctrl_pads,
 	.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),
 	.gpr_compatible = "fsl,imx6ul-iomuxc-gpr",
 };
 
-static struct of_device_id imx6ul_pinctrl_of_match[] = {
-	{ .compatible = "fsl,imx6ul-iomuxc", },
+static const struct imx_pinctrl_soc_info imx6ull_snvs_pinctrl_info = {
+	.pins = imx6ull_snvs_pinctrl_pads,
+	.npins = ARRAY_SIZE(imx6ull_snvs_pinctrl_pads),
+	.flags = ZERO_OFFSET_VALID,
+};
+
+static const struct of_device_id imx6ul_pinctrl_of_match[] = {
+	{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
+	{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
 	{ /* sentinel */ }
 };
 
 static int imx6ul_pinctrl_probe(struct platform_device *pdev)
 {
-	return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info);
+	const struct imx_pinctrl_soc_info *pinctrl_info;
+
+	pinctrl_info = of_device_get_match_data(&pdev->dev);
+	if (!pinctrl_info)
+		return -ENODEV;
+
+	return imx_pinctrl_probe(pdev, pinctrl_info);
 }
 
 static struct platform_driver imx6ul_pinctrl_driver = {
-- 
2.15.1

^ permalink raw reply related

* [PATCH 12/14] iio: adc: at91-sama5d2_adc: support for position and pressure channels
From: Jonathan Cameron @ 2018-01-06 15:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <25045512-f372-3f25-e84f-ed809db9dde3@microchip.com>

On Thu, 4 Jan 2018 17:17:54 +0200
Eugen Hristev <eugen.hristev@microchip.com> wrote:

> On 29.12.2017 19:02, Jonathan Cameron wrote:
> > On Fri, 22 Dec 2017 17:07:19 +0200
> > Eugen Hristev <eugen.hristev@microchip.com> wrote:
> >   
> >> The ADC IP supports position and pressure measurements for a touchpad
> >> connected on channels 0,1,2,3 for a 4-wire touchscreen with pressure
> >> measurement support.
> >> Using the inkern API, a driver can request a trigger and read the
> >> channel values from the ADC.
> >> The implementation provides a trigger named "touch" which can be
> >> connected to a consumer driver.
> >> Once a driver connects and attaches a pollfunc to this trigger, the
> >> configure trigger callback is called, and then the ADC driver will
> >> initialize pad measurement.
> >> First step is to enable touchscreen 4wire support and enable
> >> pen detect IRQ.
> >> Once a pen is detected, a periodic trigger is setup to trigger every
> >> 2 ms (e.g.) and sample the resistive touchscreen values. The trigger poll
> >> is called, and the consumer driver is then woke up, and it can read the
> >> respective channels for the values : X, and Y for position and pressure
> >> channel.
> >> Because only one trigger can be active in hardware in the same time,
> >> while touching the pad, the ADC will block any attempt to use the
> >> triggered buffer. Same, conversions using the software trigger are also
> >> impossible (since the periodic trigger is setup).
> >> If some driver wants to attach while the trigger is in use, it will
> >> also fail.
> >> Once the pen is not detected anymore, the trigger is free for use (hardware
> >> or software trigger, with or without DMA).
> >> Channels 0,1,2 and 3 are unavailable if a touchscreen is enabled.
> >>
> >> Some parts of this patch are based on initial original work by
> >> Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
> >>  
> > OK, so comments inline.
> > 
> > What I'm missing currently though is an explanation of why the slightly
> > more standard arrangement of using a callback buffer doesn't work here.
> > The only addition I think you need to do that is to allow a consumer to
> > request a particular trigger.  I also think some of the other provisions
> > could be handled using standard features and slightly reducing the flexibility.
> > I don't know for example if it's useful to allow other channels to be
> > read when touch is not in progress or not.
> > 
> > So restrictions:
> > 
> > 1. Touch screen channels can only be read when touch is enabled.
> >   - use the available_scan_masks to control this. Or the callback that lets
> >     you do the same dynamically.
> > 2. You need to push these channels to your consumer driver.
> >   - register a callback buffer rather than jumping through the hoops to
> >     insert your own pollfunc.  That will call a function in your
> >     consumer, providing the data from the 3 channels directly.
> > 3. You need to make sure it is using the right driver.  For that you
> >     will I think need a new interface.
> > 
> > Various other comments inline. I may well be missing something as this is
> > a fair bit of complex code to read - if so then next version should have
> > a clear cover letter describing why this more standard approach can't be
> > used.  
> 
> Hello Jonathan and thanks for the review of my patch series,
> 
> before starting and working over the required modifications and 
> suggestions that you sent me, I want to be a little more explicit about 
> the design of my implementation.
> Hope this will clarify some things, and maybe I can as well understand 
> better what you have in mind to support this feature set.
> 
> Why have I picked a pollfunction: We discussed a while back on the 
> mailing list that you do not have an inkern mechanism to expose the 
> triggers to other drivers, and that it may be a good idea to have it for 
> such kind of actually multi function device, instead of having a MFD 
> driver, an ADC driver, and an Input driver, all sharing the same 
> register map, the same IRQ , etc, with some kind of synchronization to 
> avoid stepping on each other for the hardware resource.

No disagreement with that principle.

> So I considered to expose the trigger by attaching and detaching 
> pollfunctions to it. Which is the main thing what we use a trigger for.

Hmm. It's definitely one approach. But we do already have other drivers
where the trigger is controlled by a consumer and to my mind that
is a cleaner approach as it doesn't short cut the equivalent of
doing it from userspace.

drivers/iio/potentiostat/lmp91000.c does something similar though
for a rather different use. You need your consumer interface
to get the handle to the trigger in this case
(the lmp91000 is actually providing the trigger rather than
consuming it).


> 
> So, what I had in mind, was to create a consumer driver that will 
> request triggers from the IIO device just like other drivers request 
> channels (part which is already done in IIO).
> In order to do this I had to somehow wake up the consumer driver when 
> new data was available from the touchscreen. So, having the IRQ only in 
> the ADC device, and then on Pen detect and No pen detect just start or 
> stop the periodic trigger, which needs to be polled. The magic part is 
> that the consumer driver has a poll function already attached to this 
> trigger, so the poll function is just called every time we have new 
> data. The poll function is attached as an irq handler, and then we can 
> reuse all the read_raw data by using a scheduled work from the consumer 
> driver, to read the channels.

If you had done this via a callback buffer the only difference is that
the pollfunc would have been a standard one pulling the relevant channels
and passing them on down to the buffer interface which could then decide
what to do with them.

> To do this, the ADC registers a special trigger named "touch trigger" 
> which is never enabled by the ADC driver. Instead, when a pollfunc is 
> attached to it, the attach function will also configure it with enabled 
> state.

Whilst it might not make sense to enable it in the touch screen driver
I'm not sure there is strictly any reason to prevent it being so used.

> In the ADC, this means to start the touchscreen functionality. If 
> the touch is requested, it will standby and wait for pen detect IRQ.
> Once we have pen detect, we can use a periodic trigger to sample the 
> touch data, and poll the "touch" trigger. The consumer driver will wake 
> up and schedule a work , that will use the standard read raw interface 
> (inkern) that will read three virtual channels (position + pressure). 
> They are not actual hardware channels, as the touch information is being 
> received on channels 0,1,2,3, but reading these virtual channels will 
> read from different registers inside the ADC IP ( x position, y 
> position, pressure), do some computations on the data, and feed the 
> consumer with the values , hiding the behind the scenes hardware 
> specific calculations.

I wouldn't worry about whether they are real channels or not. This
is really similar to a differential ADC (some of those do the differential
digitally). Light sensors often have a number of 'real' channels used
to derive (via hideous non linear calculations) the illuminance as
it's hard to build a light sensor with the same sensitivity as the human
eye.  We have worse 'non real' channels as well such as activity channels
on some the accelerometers that report if it thinks you are walking /
running etc.
 
> After trigger is polled , the ADC will resume normal functionality, and 
> the consumer driver will continue to sleep.

So this is where I'm unsure.  Do you actually have a usecase where it
makes the sense to read from the ADC only when there is no touch?  Any
system doing that has an obvious denial of service attack - touch the
screen.

> We need to have a periodic trigger to sample the data because the actual 
> analog to digital conversion inside the IP block needs to be triggered. 
> The touchscreen data measurements cannot happen in hardware without 
> being triggered. If I try with a hrtimer to get a periodic IRQ to just 
> read the data, it will never be ready. The datasheet states that the 
> touchscreen measurements "will be attached to the conversion sequence". 
> So the periodic trigger is forcing a conversion sequence. This could be 
> done with a software trigger as well, but why the hassle to start it 
> every 2 milliseconds (or other time interval), if we can do it by 
> periodic trigger ?

Ah, one reason here would be to allow separate consumers to use the
device. In that case you'd run with a periodic trigger all the time
and have two buffers attached, the buffer_cb that is feeding your
touchscreen and another buffer to deal with the other channels
(presumably the standard one an IIO device has when using buffered
interfaces).

The buffer demux would ensure the data from the right channels
ends up in the right place.  It makes it look to the buffer
consumer like it is the only thing using / controlling the data
flow.

> Once we get the No pen IRQ, we stop the periodic trigger and it can be 
> used in another purpose (software or external as of now in the driver, 
> in the future we can add PWM trigger and Timer trigger)

This case isn't really useful though as any other use is denied
access when touch occurs.

I'll summarise what I think would work for this below.

> 
> In short, the ADC in Sama5D2 also supports touchscreen, and in 
> touchscreen mode , 4 of the channels are being used for this purpose. 
> This however, doesn't stop the ADC to use the other channels . The 
> hardware has 12 total single channels and they can be paired to have 6 
> more differential channels. The only thing that is blocked is the 
> trigger, but only if the pen is touching (when we start the periodic 
> trigger to sample the touchscreen). If the pen is not touching, an 
> external trigger or software trigger can be used without any issues (so 
> why limit the functionality, if this is available from hardware ?). 
> Because of the reason I discussed above (touchscreen sequence must be 
> triggered), we cannot use another trigger in the same time.
> 
> 
> I see your idea with the callback buffer and it's worth exploring. 
> Mainly this series was to actually show you what I had in mind about 
> supporting the resistive touchscreen, and to give you some actually 
> working code/patch, so we can discuss based on real implementation, not 
> just suppositions.

That side of things is fine.

> 
> You are right in many of the other comments that you said, and I will 
> come up with a v2 to this series. For now, I need to know if this is a 
> good or right direction in which I am going, or I should try to change 
> all the mechanism to callback buffer ? Or maybe I am totally in a bad 
> direction ?
> The requirements are that the consumer driver needs to be somehow woke 
> up for every new touch data available, and report to the input 
> subsystem. As it was done before, the at91 old driver, just creates and 
> registers an input device by itself, and then reports the position and 
> touches. I was thinking that with this trigger consumer implementation, 
> things can be better in terms of subsystem separation and support.
> 
> Thanks again and let me know of your thoughts,
> 
> Eugen

So a couple of things come to mind on how I'd structure this.
So what we have (very briefly)

No touch screen case:
* Generic ADC using all sorts of different triggers

Touch screen only case:
* Interrupt to indicate pen on / off
* A need to do a periodic trigger of the device but only
useful when touch is in progress.

Touch screen and other users:
* Interrupt to indicate pen on / off
* Periodic trigger needed for touchscreen when touch in progress.
* Do not have denial of service on other channels.

First two cases are easy enough by having a magic trigger, third
case is harder.
If we have the touchscreen then I would drop support for direct access to
to ADC channels whilst it's in use (so no sysfs - or emulate it if you
really want it by stashing results from scans done when touch is in
progress).

Have your touch screen channels just as normal additional channels,
but only via the buffered interface (no _RAW attribute).
If someone sets up to read them via buffered interface with
a different trigger I think they'll get values - whether they
are right is dependent (if I understand correctly) on whether
there is a touch in progress.  So no harm done and it'll make
the logic simpler.

The moment touch is opened and acquires the IIO channels
fix the trigger (may need new interface) to the periodic one
that you were enabling and disabling on touch.
Things get dicey if there is an existing user so you may
have to do it on driver probe rather than open of the input
device if we effectively want touch to have the highest
priority use of the ADC.

If other channels are enabled for buffered mode then note
this in the driver and have the periodic trigger on all the
time (to ensure they keep getting read)  This will pass
garbage to your touch screen driver, but it'll remove it due
to the pressure value being too low so no harm there.

Normal path will work for non touch channels (and in theory
the touch ones if they are turned on) via IIO buffer
interface.  It'll be restricted in form due to the needs of
the touch driver, but better than nothing and should cover
most usecases.

Now the interrupt on / off on touch bit becomes an optimization
in the case of only the buffer_cb being attached.

I think that fits cleanly in the current IIO framework and
looks more similar to our existing provider consumer approaches.

Still needs the hooks to get hold of the trigger though so
as to be able to tell the ADC which one to use. So rather
than being a trigger consumer interface, it's more of a trigger
configuration interface..  Exact term doesn't matter though.

Jonathan

> 
> 
> 
> [...]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v9 0/7] Handle guest RAS Error in KVM and kernel
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

This series patches mainly do below things:

1. Trap guest RAS ERR* registers accesses to EL2 from Non-secure EL1,
   KVM will will do a minimum simulation, these registers are simulated
   to RAZ/WI in KVM.
2. Route guest synchronous External Abort to EL2. If it is also routed
   to EL3 by firmware at the same time, system will trap to EL3 firmware instead
   of EL2 KVM, then firmware judges whether EL2 routing is enabled, if enabled,
   jump back to EL2 KVM, otherwise jump back to EL1 host kernel.
3. Enable APEI ARv8 SEI notification to parse the CPER records for SError
   in the ACPI GHES driver, KVM will call handle_guest_sei() to let ACPI
   driver to parse the CPER recorded for SError which happened in the guest
4. If ACPI driver parsed the CPER record failed, KVM will classify the Error
   through Exception Syndrome Register and do different approaches according
   to Asynchronous Error Type
5. If the guest RAS SError is not propagated and not consumed, this exception
   is precise, we temporarily shut down the VM to isolate the error. For other
   Asynchronous Error Type, KVM directly injects virtual SError with IMPLEMENTATION
   DEFINED ESR or KVM panic if the error is fatal. For the RAS extension, guest
   virtual ESR must be set, because all-zero  means 'RAS error: Uncategorized' instead
   of 'no valid ISS', so set this ESR to IMPLEMENTATION DEFINED by default if user space
   does not specify it.

change since v8:
1. update the patch [1/7] and [2/7] to align this serie.
   https://www.spinics.net/lists/arm-kernel/msg623513.html
   https://www.spinics.net/lists/arm-kernel/msg623520.html
2. In kvm ,check handle_guest_sei()'s return value. If this function return true, stop
   classifying errors.
3. Temporarily shut down the VM to isolate the error for recoverable error (UER)
4. update some patch's commit messages and clean some patches

Dongjiu Geng (5):
  acpi: apei: Add SEI notification type support for ARMv8
  KVM: arm64: Trap RAS error registers and set HCR_EL2's TERR & TEA
  arm64: kvm: Introduce KVM_ARM_SET_SERROR_ESR ioctl
  arm64: kvm: Set Virtual SError Exception Syndrome for guest
  arm64: kvm: handle guest SError Interrupt by categorization

James Morse (1):
  KVM: arm64: Save ESR_EL2 on guest SError

Xie XiuQi (1):
  arm64: cpufeature: Detect CPU RAS Extentions

 Documentation/virtual/kvm/api.txt    | 11 ++++++
 arch/arm/include/asm/kvm_host.h      |  1 +
 arch/arm/kvm/guest.c                 |  9 +++++
 arch/arm64/Kconfig                   | 16 +++++++++
 arch/arm64/include/asm/cpucaps.h     |  3 +-
 arch/arm64/include/asm/esr.h         | 11 ++++++
 arch/arm64/include/asm/kvm_arm.h     |  2 ++
 arch/arm64/include/asm/kvm_emulate.h | 17 +++++++++
 arch/arm64/include/asm/kvm_host.h    |  2 ++
 arch/arm64/include/asm/sysreg.h      | 15 ++++++++
 arch/arm64/include/asm/system_misc.h |  1 +
 arch/arm64/kernel/cpufeature.c       | 13 +++++++
 arch/arm64/kvm/guest.c               | 14 ++++++++
 arch/arm64/kvm/handle_exit.c         | 68 +++++++++++++++++++++++++++++++++---
 arch/arm64/kvm/hyp/switch.c          | 25 +++++++++++--
 arch/arm64/kvm/inject_fault.c        | 13 ++++++-
 arch/arm64/kvm/reset.c               |  3 ++
 arch/arm64/kvm/sys_regs.c            | 10 ++++++
 arch/arm64/mm/fault.c                | 16 +++++++++
 drivers/acpi/apei/Kconfig            | 15 ++++++++
 drivers/acpi/apei/ghes.c             | 53 ++++++++++++++++++++++++++++
 include/acpi/ghes.h                  |  1 +
 include/uapi/linux/kvm.h             |  3 ++
 virt/kvm/arm/arm.c                   |  7 ++++
 24 files changed, 320 insertions(+), 9 deletions(-)

-- 
1.9.1

^ permalink raw reply

* [PATCH v9 1/7] arm64: cpufeature: Detect CPU RAS Extentions
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

From: Xie XiuQi <xiexiuqi@huawei.com>

ARM's v8.2 Extentions add support for Reliability, Availability and
Serviceability (RAS). On CPUs with these extensions system software
can use additional barriers to isolate errors and determine if faults
are pending.

Add cpufeature detection and a barrier in the context-switch code.
There is no need to use alternatives for this as CPUs that don't
support this feature will treat the instruction as a nop.

Platform level RAS support may require additional firmware support.

Signed-off-by: Xie XiuQi <xiexiuqi@huawei.com>
[Rebased added config option, reworded commit message]
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
 arch/arm64/Kconfig               | 16 ++++++++++++++++
 arch/arm64/include/asm/cpucaps.h |  3 ++-
 arch/arm64/include/asm/sysreg.h  |  2 ++
 arch/arm64/kernel/cpufeature.c   | 13 +++++++++++++
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 0df64a6..cc00d10 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -973,6 +973,22 @@ config ARM64_PMEM
 	  operations if DC CVAP is not supported (following the behaviour of
 	  DC CVAP itself if the system does not define a point of persistence).
 
+config ARM64_RAS_EXTN
+	bool "Enable support for RAS CPU Extensions"
+	default y
+	help
+	  CPUs that support the Reliability, Availability and Serviceability
+	  (RAS) Extensions, part of ARMv8.2 are able to track faults and
+	  errors, classify them and report them to software.
+
+	  On CPUs with these extensions system software can use additional
+	  barriers to determine if faults are pending and read the
+	  classification from a new set of registers.
+
+	  Selecting this feature will allow the kernel to use these barriers
+	  and access the new registers if the system supports the extension.
+	  Platform RAS features may additionally depend on firmware support.
+
 endmenu
 
 config ARM64_MODULE_CMODEL_LARGE
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 8da6216..4820d44 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -40,7 +40,8 @@
 #define ARM64_WORKAROUND_858921			19
 #define ARM64_WORKAROUND_CAVIUM_30115		20
 #define ARM64_HAS_DCPOP				21
+#define ARM64_HAS_RAS_EXTN			22
 
-#define ARM64_NCAPS				22
+#define ARM64_NCAPS				23
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index f707fed..64e2a80 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -332,6 +332,7 @@
 #define ID_AA64ISAR1_DPB_SHIFT		0
 
 /* id_aa64pfr0 */
+#define ID_AA64PFR0_RAS_SHIFT		28
 #define ID_AA64PFR0_GIC_SHIFT		24
 #define ID_AA64PFR0_ASIMD_SHIFT		20
 #define ID_AA64PFR0_FP_SHIFT		16
@@ -340,6 +341,7 @@
 #define ID_AA64PFR0_EL1_SHIFT		4
 #define ID_AA64PFR0_EL0_SHIFT		0
 
+#define ID_AA64PFR0_RAS_V1		0x1
 #define ID_AA64PFR0_FP_NI		0xf
 #define ID_AA64PFR0_FP_SUPPORTED	0x0
 #define ID_AA64PFR0_ASIMD_NI		0xf
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 21e2c95..4846974 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -125,6 +125,7 @@ static int __init register_cpu_hwcaps_dumper(void)
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_RAS_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
@@ -900,6 +901,18 @@ static bool has_no_fpsimd(const struct arm64_cpu_capabilities *entry, int __unus
 		.min_field_value = 1,
 	},
 #endif
+#ifdef CONFIG_ARM64_RAS_EXTN
+	{
+		.desc = "RAS Extension Support",
+		.capability = ARM64_HAS_RAS_EXTN,
+		.def_scope = SCOPE_SYSTEM,
+		.matches = has_cpuid_feature,
+		.sys_reg = SYS_ID_AA64PFR0_EL1,
+		.sign = FTR_UNSIGNED,
+		.field_pos = ID_AA64PFR0_RAS_SHIFT,
+		.min_field_value = ID_AA64PFR0_RAS_V1,
+	},
+#endif /* CONFIG_ARM64_RAS_EXTN */
 	{},
 };
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v9 2/7] KVM: arm64: Save ESR_EL2 on guest SError
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

From: James Morse <james.morse@arm.com>

When we exit a guest due to an SError the vcpu fault info isn't updated
with the ESR. Today this is only done for traps.

The v8.2 RAS Extensions define ISS values for SError. Update the vcpu's
fault_info with the ESR on SError so that handle_exit() can determine
if this was a RAS SError and decode its severity.

Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/kvm/hyp/switch.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 945e79c..fb5a538 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -228,11 +228,12 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar)
 
 static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
 {
-	u64 esr = read_sysreg_el2(esr);
-	u8 ec = ESR_ELx_EC(esr);
+	u8 ec;
+	u64 esr;
 	u64 hpfar, far;
 
-	vcpu->arch.fault.esr_el2 = esr;
+	esr = vcpu->arch.fault.esr_el2;
+	ec = ESR_ELx_EC(esr);
 
 	if (ec != ESR_ELx_EC_DABT_LOW && ec != ESR_ELx_EC_IABT_LOW)
 		return true;
@@ -313,6 +314,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	exit_code = __guest_enter(vcpu, host_ctxt);
 	/* And we're baaack! */
 
+	if (ARM_EXCEPTION_CODE(exit_code) != ARM_EXCEPTION_IRQ)
+		vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
 	/*
 	 * We're using the raw exception code in order to only process
 	 * the trap if no SError is pending. We will come back to the
-- 
1.9.1

^ permalink raw reply related

* [PATCH v9 3/7] acpi: apei: Add SEI notification type support for ARMv8
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

ARMv8.2 requires implementation of the RAS extension. In
this extension, it adds SEI(SError Interrupt) notification
type, this patch adds new GHES error source SEI handling
functions. This error source parsing and handling method
is similar with the SEA.

Expose API ghes_notify_sei() to external users. External
modules can call this exposed API to parse APEI table and
handle the SEI notification.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
 drivers/acpi/apei/Kconfig | 15 ++++++++++++++
 drivers/acpi/apei/ghes.c  | 53 +++++++++++++++++++++++++++++++++++++++++++++++
 include/acpi/ghes.h       |  1 +
 3 files changed, 69 insertions(+)

diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 52ae543..ff4afc3 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -55,6 +55,21 @@ config ACPI_APEI_SEA
 	  option allows the OS to look for such hardware error record, and
 	  take appropriate action.
 
+config ACPI_APEI_SEI
+	bool "APEI SError(System Error) Interrupt logging/recovering support"
+	depends on ARM64 && ACPI_APEI_GHES
+	default y
+	help
+	  This option should be enabled if the system supports
+	  firmware first handling of SEI (SError interrupt).
+
+	  SEI happens with asynchronous external abort for errors on device
+	  memory reads on ARMv8 systems. If a system supports firmware first
+	  handling of SEI, the platform analyzes and handles hardware error
+	  notifications from SEI, and it may then form a hardware error record for
+	  the OS to parse and handle. This option allows the OS to look for
+	  such hardware error record, and take appropriate action.
+
 config ACPI_APEI_MEMORY_FAILURE
 	bool "APEI memory error recovering support"
 	depends on ACPI_APEI && MEMORY_FAILURE
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 6a3f824..67cd3a7 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -855,6 +855,46 @@ static inline void ghes_sea_add(struct ghes *ghes) { }
 static inline void ghes_sea_remove(struct ghes *ghes) { }
 #endif /* CONFIG_ACPI_APEI_SEA */
 
+#ifdef CONFIG_ACPI_APEI_SEI
+static LIST_HEAD(ghes_sei);
+
+/*
+ * Return 0 only if one of the SEI error sources successfully reported an error
+ * record sent from the firmware.
+ */
+int ghes_notify_sei(void)
+{
+	struct ghes *ghes;
+	int ret = -ENOENT;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(ghes, &ghes_sei, list) {
+		if (!ghes_proc(ghes))
+			ret = 0;
+	}
+	rcu_read_unlock();
+	return ret;
+}
+
+static void ghes_sei_add(struct ghes *ghes)
+{
+	mutex_lock(&ghes_list_mutex);
+	list_add_rcu(&ghes->list, &ghes_sei);
+	mutex_unlock(&ghes_list_mutex);
+}
+
+static void ghes_sei_remove(struct ghes *ghes)
+{
+	mutex_lock(&ghes_list_mutex);
+	list_del_rcu(&ghes->list);
+	mutex_unlock(&ghes_list_mutex);
+	synchronize_rcu();
+}
+#else /* CONFIG_ACPI_APEI_SEI */
+static inline void ghes_sei_add(struct ghes *ghes) { }
+static inline void ghes_sei_remove(struct ghes *ghes) { }
+#endif /* CONFIG_ACPI_APEI_SEI */
+
 #ifdef CONFIG_HAVE_ACPI_APEI_NMI
 /*
  * printk is not safe in NMI context.  So in NMI handler, we allocate
@@ -1086,6 +1126,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
 			goto err;
 		}
 		break;
+	case ACPI_HEST_NOTIFY_SEI:
+		if (!IS_ENABLED(CONFIG_ACPI_APEI_SEI)) {
+			pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEI is not supported!\n",
+				generic->header.source_id);
+		goto err;
+	}
+	break;
 	case ACPI_HEST_NOTIFY_NMI:
 		if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
 			pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
@@ -1158,6 +1205,9 @@ static int ghes_probe(struct platform_device *ghes_dev)
 	case ACPI_HEST_NOTIFY_SEA:
 		ghes_sea_add(ghes);
 		break;
+	case ACPI_HEST_NOTIFY_SEI:
+		ghes_sei_add(ghes);
+		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		ghes_nmi_add(ghes);
 		break;
@@ -1211,6 +1261,9 @@ static int ghes_remove(struct platform_device *ghes_dev)
 	case ACPI_HEST_NOTIFY_SEA:
 		ghes_sea_remove(ghes);
 		break;
+	case ACPI_HEST_NOTIFY_SEI:
+		ghes_sei_remove(ghes);
+		break;
 	case ACPI_HEST_NOTIFY_NMI:
 		ghes_nmi_remove(ghes);
 		break;
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 8feb0c8..9ba59e2 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -120,5 +120,6 @@ static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
 	     section = acpi_hest_get_next(section))
 
 int ghes_notify_sea(void);
+int ghes_notify_sei(void);
 
 #endif /* GHES_H */
-- 
1.9.1

^ permalink raw reply related

* [PATCH v9 4/7] KVM: arm64: Trap RAS error registers and set HCR_EL2's TERR & TEA
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

ARMv8.2 adds a new bit HCR_EL2.TEA which routes synchronous external
aborts to EL2, and adds a trap control bit HCR_EL2.TERR which traps
all Non-secure EL1&0 error record accesses to EL2.

This patch enables the two bits for the guest OS, guaranteeing that
KVM takes external aborts and traps attempts to access the physical
error registers.

ERRIDR_EL1 advertises the number of error records, we return
zero meaning we can treat all the other registers as RAZ/WI too.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
[removed specific emulation, use trap_raz_wi() directly for everything,
 rephrased parts of the commit message]
Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h     |  2 ++
 arch/arm64/include/asm/kvm_emulate.h |  7 +++++++
 arch/arm64/include/asm/sysreg.h      | 10 ++++++++++
 arch/arm64/kvm/sys_regs.c            | 10 ++++++++++
 4 files changed, 29 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 61d694c..1188272 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,8 @@
 #include <asm/types.h>
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_TEA		(UL(1) << 37)
+#define HCR_TERR	(UL(1) << 36)
 #define HCR_E2H		(UL(1) << 34)
 #define HCR_ID		(UL(1) << 33)
 #define HCR_CD		(UL(1) << 32)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index e5df3fc..555b28b 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -47,6 +47,13 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 	vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
 	if (is_kernel_in_hyp_mode())
 		vcpu->arch.hcr_el2 |= HCR_E2H;
+	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
+		/* route synchronous external abort exceptions to EL2 */
+		vcpu->arch.hcr_el2 |= HCR_TEA;
+		/* trap error record accesses */
+		vcpu->arch.hcr_el2 |= HCR_TERR;
+	}
+
 	if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
 		vcpu->arch.hcr_el2 &= ~HCR_RW;
 }
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 64e2a80..47b967d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -169,6 +169,16 @@
 #define SYS_AFSR0_EL1			sys_reg(3, 0, 5, 1, 0)
 #define SYS_AFSR1_EL1			sys_reg(3, 0, 5, 1, 1)
 #define SYS_ESR_EL1			sys_reg(3, 0, 5, 2, 0)
+
+#define SYS_ERRIDR_EL1			sys_reg(3, 0, 5, 3, 0)
+#define SYS_ERRSELR_EL1			sys_reg(3, 0, 5, 3, 1)
+#define SYS_ERXFR_EL1			sys_reg(3, 0, 5, 4, 0)
+#define SYS_ERXCTLR_EL1			sys_reg(3, 0, 5, 4, 1)
+#define SYS_ERXSTATUS_EL1		sys_reg(3, 0, 5, 4, 2)
+#define SYS_ERXADDR_EL1			sys_reg(3, 0, 5, 4, 3)
+#define SYS_ERXMISC0_EL1		sys_reg(3, 0, 5, 5, 0)
+#define SYS_ERXMISC1_EL1		sys_reg(3, 0, 5, 5, 1)
+
 #define SYS_FAR_EL1			sys_reg(3, 0, 6, 0, 0)
 #define SYS_PAR_EL1			sys_reg(3, 0, 7, 4, 0)
 
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 2e070d3..2b1fafa 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -953,6 +953,16 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
 	{ SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
 	{ SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
 	{ SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
+
+	{ SYS_DESC(SYS_ERRIDR_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERRSELR_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXFR_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXCTLR_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXSTATUS_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXADDR_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi },
+	{ SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi },
+
 	{ SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 },
 	{ SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 },
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v9 5/7] arm64: kvm: Introduce KVM_ARM_SET_SERROR_ESR ioctl
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

The ARM64 RAS SError Interrupt(SEI) syndrome value is specific to the
guest and user space needs a way to tell KVM this value. So we add a
new ioctl. Before user space specifies the Exception Syndrome Register
ESR(ESR), it firstly checks that whether KVM has the capability to
set the guest ESR, If has, will set it. Otherwise, nothing to do.

For this ESR specifying, Only support for AArch64, not support AArch32.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
---
change the name to KVM_CAP_ARM_INJECT_SERROR_ESR instead of
XXXXX_ARM_RAS_EXTENSION, suggested here

https://patchwork.kernel.org/patch/9925203/
---
 Documentation/virtual/kvm/api.txt | 11 +++++++++++
 arch/arm/include/asm/kvm_host.h   |  1 +
 arch/arm/kvm/guest.c              |  9 +++++++++
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/guest.c            |  5 +++++
 arch/arm64/kvm/reset.c            |  3 +++
 include/uapi/linux/kvm.h          |  3 +++
 virt/kvm/arm/arm.c                |  7 +++++++
 8 files changed, 40 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index e63a35f..6dfb9fc 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -4347,3 +4347,14 @@ This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr.  Its
 value is used to denote the target vcpu for a SynIC interrupt.  For
 compatibilty, KVM initializes this msr to KVM's internal vcpu index.  When this
 capability is absent, userspace can still query this msr's value.
+
+8.13 KVM_CAP_ARM_SET_SERROR_ESR
+
+Architectures: arm, arm64
+
+This capability indicates that userspace can specify syndrome value reported to
+guest OS when guest takes a virtual SError interrupt exception.
+If KVM has this capability, userspace can only specify the ISS field for the ESR
+syndrome, can not specify the EC field which is not under control by KVM.
+If this virtual SError is taken to EL1 using AArch64, this value will be reported
+into ISS filed of ESR_EL1
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 4a879f6..6cf5c7b 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -211,6 +211,7 @@ struct kvm_vcpu_stat {
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
 int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_sei_esr(struct kvm_vcpu *vcpu, u32 *syndrome);
 unsigned long kvm_call_hyp(void *hypfn, ...);
 void force_vm_exit(const cpumask_t *mask);
 
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 1e0784e..1e15fa2 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -248,6 +248,15 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 	return -EINVAL;
 }
 
+/*
+ * we only support guest SError syndrome specifying
+ * for ARM64, not support it for ARM32.
+ */
+int kvm_arm_set_sei_esr(struct kvm_vcpu *vcpu, u32 *syndrome)
+{
+	return -EINVAL;
+}
+
 int __attribute_const__ kvm_target_cpu(void)
 {
 	switch (read_cpuid_part()) {
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e923b58..769cc58 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -317,6 +317,7 @@ struct kvm_vcpu_stat {
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
 int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_sei_esr(struct kvm_vcpu *vcpu, u32 *syndrome);
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657..738ae90 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -277,6 +277,11 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 	return -EINVAL;
 }
 
+int kvm_arm_set_sei_esr(struct kvm_vcpu *vcpu, u32 *syndrome)
+{
+	return -EINVAL;
+}
+
 int __attribute_const__ kvm_target_cpu(void)
 {
 	unsigned long implementor = read_cpuid_implementor();
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 3256b92..38c8a64 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_ARM_PMU_V3:
 		r = kvm_arm_support_pmu_v3();
 		break;
+	case KVM_CAP_ARM_INJECT_SERROR_ESR:
+		r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
+		break;
 	case KVM_CAP_SET_GUEST_DEBUG:
 	case KVM_CAP_VCPU_ATTRIBUTES:
 		r = 1;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 7e99999..0c861c4 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -931,6 +931,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_PPC_SMT_POSSIBLE 147
 #define KVM_CAP_HYPERV_SYNIC2 148
 #define KVM_CAP_HYPERV_VP_INDEX 149
+#define KVM_CAP_ARM_INJECT_SERROR_ESR 150
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1357,6 +1358,8 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_S390_CMMA_MIGRATION */
 #define KVM_S390_GET_CMMA_BITS      _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
 #define KVM_S390_SET_CMMA_BITS      _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
+/* Available with KVM_CAP_ARM_INJECT_SERROR_ESR */
+#define KVM_ARM_INJECT_SERROR_ESR   _IOW(KVMIO,  0xba, __u32)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 95cba07..60dea5f 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1027,6 +1027,13 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 			return -EFAULT;
 		return kvm_arm_vcpu_has_attr(vcpu, &attr);
 	}
+	case KVM_ARM_INJECT_SERROR_ESR: {
+		u32 syndrome;
+
+		if (copy_from_user(&syndrome, argp, sizeof(syndrome)))
+			return -EFAULT;
+		return kvm_arm_set_sei_esr(vcpu, &syndrome);
+	}
 	default:
 		return -EINVAL;
 	}
-- 
1.9.1

^ permalink raw reply related

* [PATCH v9 6/7] arm64: kvm: Set Virtual SError Exception Syndrome for guest
From: Dongjiu Geng @ 2018-01-06 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515254577-6460-1-git-send-email-gengdongjiu@huawei.com>

RAS Extension add a VSESR_EL2 register which can provide
the syndrome value reported to software on taking a virtual
SError interrupt exception. This patch supports to specify
this Syndrome.

In the RAS Extensions we can not set all-zero syndrome value
for SError, which means 'RAS error: Uncategorized' instead of
'no valid ISS'. So set it to IMPLEMENTATION DEFINED syndrome
by default.

We also need to support userspace to specify a valid syndrome
value, Because in some case, the recovery is driven by userspace.
This patch can support that userspace specify it.

In the guest/host world switch, restore this value to VSESR_EL2
only when HCR_EL2.VSE is set. This value no need to be saved
because it is stale vale when guest exit.

Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
[Set an impdef ESR for Virtual-SError]
Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h | 10 ++++++++++
 arch/arm64/include/asm/kvm_host.h    |  1 +
 arch/arm64/include/asm/sysreg.h      |  3 +++
 arch/arm64/kvm/guest.c               | 11 ++++++++++-
 arch/arm64/kvm/hyp/switch.c          | 16 ++++++++++++++++
 arch/arm64/kvm/inject_fault.c        | 13 ++++++++++++-
 6 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 555b28b..73c84d0 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -155,6 +155,16 @@ static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 	return vcpu->arch.fault.esr_el2;
 }
 
+static inline u32 kvm_vcpu_get_vsesr(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.fault.vsesr_el2;
+}
+
+static inline void kvm_vcpu_set_vsesr(struct kvm_vcpu *vcpu, unsigned long val)
+{
+	vcpu->arch.fault.vsesr_el2 = val;
+}
+
 static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
 	u32 esr = kvm_vcpu_get_hsr(vcpu);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 769cc58..53d1d81 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -88,6 +88,7 @@ struct kvm_vcpu_fault_info {
 	u32 esr_el2;		/* Hyp Syndrom Register */
 	u64 far_el2;		/* Hyp Fault Address Register */
 	u64 hpfar_el2;		/* Hyp IPA Fault Address Register */
+	u32 vsesr_el2;          /* Virtual SError Exception Syndrome Register */
 };
 
 /*
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 47b967d..3b035cc 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -86,6 +86,9 @@
 #define REG_PSTATE_PAN_IMM		sys_reg(0, 0, 4, 0, 4)
 #define REG_PSTATE_UAO_IMM		sys_reg(0, 0, 4, 0, 3)
 
+/* virtual SError exception syndrome register */
+#define REG_VSESR_EL2                  sys_reg(3, 4, 5, 2, 3)
+
 #define SET_PSTATE_PAN(x) __emit_inst(0xd5000000 | REG_PSTATE_PAN_IMM |	\
 				      (!!x)<<8 | 0x1f)
 #define SET_PSTATE_UAO(x) __emit_inst(0xd5000000 | REG_PSTATE_UAO_IMM |	\
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 738ae90..ffad42b 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -279,7 +279,16 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
 int kvm_arm_set_sei_esr(struct kvm_vcpu *vcpu, u32 *syndrome)
 {
-	return -EINVAL;
+	u64 reg = *syndrome;
+
+	/* inject virtual system Error or asynchronous abort */
+	kvm_inject_vabt(vcpu);
+
+	if (reg)
+		/* set vsesr_el2[24:0] with value that user space specified */
+		kvm_vcpu_set_vsesr(vcpu, reg & ESR_ELx_ISS_MASK);
+
+	return 0;
 }
 
 int __attribute_const__ kvm_target_cpu(void)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fb5a538..7f08a5d 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -67,6 +67,14 @@ static hyp_alternate_select(__activate_traps_arch,
 			    __activate_traps_nvhe, __activate_traps_vhe,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
+static void __hyp_text __sysreg_set_vsesr(struct kvm_vcpu *vcpu, u64 value)
+{
+	if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) &&
+			       (value & HCR_VSE))
+		write_sysreg_s(kvm_vcpu_get_vsesr(vcpu), REG_VSESR_EL2);
+}
+
+
 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
 	u64 val;
@@ -86,6 +94,14 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 		isb();
 	}
 	write_sysreg(val, hcr_el2);
+
+	/*
+	 * If the virtual SError interrupt is taken to EL1 using AArch64,
+	 * then VSESR_EL2 provides the syndrome value reported in ISS field
+	 * of ESR_EL1.
+	 */
+	__sysreg_set_vsesr(vcpu, val);
+
 	/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
 	write_sysreg(1 << 15, hstr_el2);
 	/*
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 3556715..fb94b5e 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -246,14 +246,25 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 		inject_undef64(vcpu);
 }
 
+static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
+{
+	kvm_vcpu_set_vsesr(vcpu, esr);
+	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+}
+
 /**
  * kvm_inject_vabt - inject an async abort / SError into the guest
  * @vcpu: The VCPU to receive the exception
  *
  * It is assumed that this code is called from the VCPU thread and that the
  * VCPU therefore is not currently executing guest code.
+ *
+ * Systems with the RAS Extensions specify an imp-def ESR (ISV/IDS = 1) with
+ * the remaining ISS all-zeros so that this error is not interpreted as an
+ * uncatagorized RAS error. Without the RAS Extensions we can't specify an ESR
+ * value, so the CPU generates an imp-def value.
  */
 void kvm_inject_vabt(struct kvm_vcpu *vcpu)
 {
-	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+	pend_guest_serror(vcpu, ESR_ELx_ISV);
 }
-- 
1.9.1

^ permalink raw reply related


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