Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/5] perf s390: add regs_query_register_offset()
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512137948-31729-1-git-send-email-brueckner@linux.vnet.ibm.com>

The regs_query_register_offset() helper function converts
register name like "%r0" to an offset of a register in user_pt_regs
It is required by the BPF prologue generator.

The user_pt_regs structure was recently added to "asm/ptrace.h".
Hence, update tools/perf/check-headers.sh to keep the header file
in sync with kernel changes.

Suggested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-and-tested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 tools/perf/arch/s390/Makefile          |  1 +
 tools/perf/arch/s390/util/dwarf-regs.c | 32 +++++++++++++++++++++++++++++---
 tools/perf/check-headers.sh            |  1 +
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
index 21322e0..09ba923 100644
--- a/tools/perf/arch/s390/Makefile
+++ b/tools/perf/arch/s390/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
 endif
 HAVE_KVM_STAT_SUPPORT := 1
+PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index f47576c..a8ace5c 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -2,17 +2,43 @@
 /*
  * Mapping of DWARF debug register numbers into register names.
  *
- *    Copyright IBM Corp. 2010
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ * Copyright IBM Corp. 2010, 2017
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *	      Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  *
  */
 
+#include <errno.h>
 #include <stddef.h>
-#include <dwarf-regs.h>
+#include <stdlib.h>
 #include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <string.h>
+#include <dwarf-regs.h>
 #include "dwarf-regs-table.h"
 
 const char *get_arch_regstr(unsigned int n)
 {
 	return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n];
 }
+
+/*
+ * Convert the register name into an offset to struct pt_regs (kernel).
+ * This is required by the BPF prologue generator.  The BPF
+ * program is called in the BPF overflow handler in the perf
+ * core.
+ */
+int regs_query_register_offset(const char *name)
+{
+	unsigned long gpr;
+
+	if (!name || strncmp(name, "%r", 2))
+		return -EINVAL;
+
+	errno = 0;
+	gpr = strtoul(name + 2, NULL, 10);
+	if (errno || gpr >= 16)
+		return -EINVAL;
+
+	return offsetof(user_pt_regs, gprs) + 8 * gpr;
+}
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh
index 77406d2..6db9d80 100755
--- a/tools/perf/check-headers.sh
+++ b/tools/perf/check-headers.sh
@@ -30,6 +30,7 @@ arch/x86/include/uapi/asm/vmx.h
 arch/powerpc/include/uapi/asm/kvm.h
 arch/s390/include/uapi/asm/kvm.h
 arch/s390/include/uapi/asm/kvm_perf.h
+arch/s390/include/uapi/asm/ptrace.h
 arch/s390/include/uapi/asm/sie.h
 arch/arm/include/uapi/asm/kvm.h
 arch/arm64/include/uapi/asm/kvm.h
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 4/5] selftests/bpf: sync kernel headers and introduce arch support in Makefile
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512137948-31729-1-git-send-email-brueckner@linux.vnet.ibm.com>

Synchronize the uapi kernel header files which solves the broken
uapi export of pt_regs.  Because of arch-specific uapi headers,
extended the include path in the Makefile.

With this change, the test_verifier program compiles and runs successfully
on s390.

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-and-tested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Shuah Khan <shuah@kernel.org>
---
 tools/arch/arm64/include/uapi/asm/bpf_perf_event.h |   9 +
 tools/arch/s390/include/uapi/asm/bpf_perf_event.h  |   9 +
 tools/arch/s390/include/uapi/asm/ptrace.h          | 471 +++++++++++++++++++++
 tools/include/uapi/asm-generic/bpf_perf_event.h    |   9 +
 tools/include/uapi/linux/bpf_perf_event.h          |   6 +-
 tools/testing/selftests/bpf/Makefile               |  14 +-
 6 files changed, 514 insertions(+), 4 deletions(-)
 create mode 100644 tools/arch/arm64/include/uapi/asm/bpf_perf_event.h
 create mode 100644 tools/arch/s390/include/uapi/asm/bpf_perf_event.h
 create mode 100644 tools/arch/s390/include/uapi/asm/ptrace.h
 create mode 100644 tools/include/uapi/asm-generic/bpf_perf_event.h

diff --git a/tools/arch/arm64/include/uapi/asm/bpf_perf_event.h b/tools/arch/arm64/include/uapi/asm/bpf_perf_event.h
new file mode 100644
index 0000000..b551b74
--- /dev/null
+++ b/tools/arch/arm64/include/uapi/asm/bpf_perf_event.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_BPF_PERF_EVENT_H__
+
+#include <asm/ptrace.h>
+
+typedef struct user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
diff --git a/tools/arch/s390/include/uapi/asm/bpf_perf_event.h b/tools/arch/s390/include/uapi/asm/bpf_perf_event.h
new file mode 100644
index 0000000..cefe7c7
--- /dev/null
+++ b/tools/arch/s390/include/uapi/asm/bpf_perf_event.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_BPF_PERF_EVENT_H__
+
+#include <asm/ptrace.h>
+
+typedef user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
diff --git a/tools/arch/s390/include/uapi/asm/ptrace.h b/tools/arch/s390/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..70f7cb2
--- /dev/null
+++ b/tools/arch/s390/include/uapi/asm/ptrace.h
@@ -0,0 +1,471 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ *  S390 version
+ *    Copyright IBM Corp. 1999, 2000
+ *    Author(s): Denis Joseph Barrow (djbarrow at de.ibm.com,barrow_dj at yahoo.com)
+ */
+
+#ifndef _UAPI_S390_PTRACE_H
+#define _UAPI_S390_PTRACE_H
+
+/*
+ * Offsets in the user_regs_struct. They are used for the ptrace
+ * system call and in entry.S
+ */
+#ifndef __s390x__
+
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x04
+#define PT_GPR0     0x08
+#define PT_GPR1     0x0C
+#define PT_GPR2     0x10
+#define PT_GPR3     0x14
+#define PT_GPR4     0x18
+#define PT_GPR5     0x1C
+#define PT_GPR6     0x20
+#define PT_GPR7     0x24
+#define PT_GPR8     0x28
+#define PT_GPR9     0x2C
+#define PT_GPR10    0x30
+#define PT_GPR11    0x34
+#define PT_GPR12    0x38
+#define PT_GPR13    0x3C
+#define PT_GPR14    0x40
+#define PT_GPR15    0x44
+#define PT_ACR0     0x48
+#define PT_ACR1     0x4C
+#define PT_ACR2     0x50
+#define PT_ACR3     0x54
+#define PT_ACR4	    0x58
+#define PT_ACR5	    0x5C
+#define PT_ACR6	    0x60
+#define PT_ACR7	    0x64
+#define PT_ACR8	    0x68
+#define PT_ACR9	    0x6C
+#define PT_ACR10    0x70
+#define PT_ACR11    0x74
+#define PT_ACR12    0x78
+#define PT_ACR13    0x7C
+#define PT_ACR14    0x80
+#define PT_ACR15    0x84
+#define PT_ORIGGPR2 0x88
+#define PT_FPC	    0x90
+/*
+ * A nasty fact of life that the ptrace api
+ * only supports passing of longs.
+ */
+#define PT_FPR0_HI  0x98
+#define PT_FPR0_LO  0x9C
+#define PT_FPR1_HI  0xA0
+#define PT_FPR1_LO  0xA4
+#define PT_FPR2_HI  0xA8
+#define PT_FPR2_LO  0xAC
+#define PT_FPR3_HI  0xB0
+#define PT_FPR3_LO  0xB4
+#define PT_FPR4_HI  0xB8
+#define PT_FPR4_LO  0xBC
+#define PT_FPR5_HI  0xC0
+#define PT_FPR5_LO  0xC4
+#define PT_FPR6_HI  0xC8
+#define PT_FPR6_LO  0xCC
+#define PT_FPR7_HI  0xD0
+#define PT_FPR7_LO  0xD4
+#define PT_FPR8_HI  0xD8
+#define PT_FPR8_LO  0XDC
+#define PT_FPR9_HI  0xE0
+#define PT_FPR9_LO  0xE4
+#define PT_FPR10_HI 0xE8
+#define PT_FPR10_LO 0xEC
+#define PT_FPR11_HI 0xF0
+#define PT_FPR11_LO 0xF4
+#define PT_FPR12_HI 0xF8
+#define PT_FPR12_LO 0xFC
+#define PT_FPR13_HI 0x100
+#define PT_FPR13_LO 0x104
+#define PT_FPR14_HI 0x108
+#define PT_FPR14_LO 0x10C
+#define PT_FPR15_HI 0x110
+#define PT_FPR15_LO 0x114
+#define PT_CR_9	    0x118
+#define PT_CR_10    0x11C
+#define PT_CR_11    0x120
+#define PT_IEEE_IP  0x13C
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x140-1
+
+#define GPR_SIZE	4
+#define CR_SIZE		4
+
+#define STACK_FRAME_OVERHEAD	96	/* size of minimum stack frame */
+
+#else /* __s390x__ */
+
+#define PT_PSWMASK  0x00
+#define PT_PSWADDR  0x08
+#define PT_GPR0     0x10
+#define PT_GPR1     0x18
+#define PT_GPR2     0x20
+#define PT_GPR3     0x28
+#define PT_GPR4     0x30
+#define PT_GPR5     0x38
+#define PT_GPR6     0x40
+#define PT_GPR7     0x48
+#define PT_GPR8     0x50
+#define PT_GPR9     0x58
+#define PT_GPR10    0x60
+#define PT_GPR11    0x68
+#define PT_GPR12    0x70
+#define PT_GPR13    0x78
+#define PT_GPR14    0x80
+#define PT_GPR15    0x88
+#define PT_ACR0     0x90
+#define PT_ACR1     0x94
+#define PT_ACR2     0x98
+#define PT_ACR3     0x9C
+#define PT_ACR4	    0xA0
+#define PT_ACR5	    0xA4
+#define PT_ACR6	    0xA8
+#define PT_ACR7	    0xAC
+#define PT_ACR8	    0xB0
+#define PT_ACR9	    0xB4
+#define PT_ACR10    0xB8
+#define PT_ACR11    0xBC
+#define PT_ACR12    0xC0
+#define PT_ACR13    0xC4
+#define PT_ACR14    0xC8
+#define PT_ACR15    0xCC
+#define PT_ORIGGPR2 0xD0
+#define PT_FPC	    0xD8
+#define PT_FPR0     0xE0
+#define PT_FPR1     0xE8
+#define PT_FPR2     0xF0
+#define PT_FPR3     0xF8
+#define PT_FPR4     0x100
+#define PT_FPR5     0x108
+#define PT_FPR6     0x110
+#define PT_FPR7     0x118
+#define PT_FPR8     0x120
+#define PT_FPR9     0x128
+#define PT_FPR10    0x130
+#define PT_FPR11    0x138
+#define PT_FPR12    0x140
+#define PT_FPR13    0x148
+#define PT_FPR14    0x150
+#define PT_FPR15    0x158
+#define PT_CR_9     0x160
+#define PT_CR_10    0x168
+#define PT_CR_11    0x170
+#define PT_IEEE_IP  0x1A8
+#define PT_LASTOFF  PT_IEEE_IP
+#define PT_ENDREGS  0x1B0-1
+
+#define GPR_SIZE	8
+#define CR_SIZE		8
+
+#define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
+
+#endif /* __s390x__ */
+
+#define NUM_GPRS	16
+#define NUM_FPRS	16
+#define NUM_CRS		16
+#define NUM_ACRS	16
+
+#define NUM_CR_WORDS	3
+
+#define FPR_SIZE	8
+#define FPC_SIZE	4
+#define FPC_PAD_SIZE	4 /* gcc insists on aligning the fpregs */
+#define ACR_SIZE	4
+
+
+#define PTRACE_OLDSETOPTIONS         21
+
+#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <linux/types.h>
+
+typedef union
+{
+	float   f;
+	double  d;
+        __u64   ui;
+	struct
+	{
+		__u32 hi;
+		__u32 lo;
+	} fp;
+} freg_t;
+
+typedef struct
+{
+	__u32   fpc;
+	__u32	pad;
+	freg_t  fprs[NUM_FPRS];              
+} s390_fp_regs;
+
+#define FPC_EXCEPTION_MASK      0xF8000000
+#define FPC_FLAGS_MASK          0x00F80000
+#define FPC_DXC_MASK            0x0000FF00
+#define FPC_RM_MASK             0x00000003
+
+/* this typedef defines how a Program Status Word looks like */
+typedef struct 
+{
+        unsigned long mask;
+        unsigned long addr;
+} __attribute__ ((aligned(8))) psw_t;
+
+#ifndef __s390x__
+
+#define PSW_MASK_PER		0x40000000UL
+#define PSW_MASK_DAT		0x04000000UL
+#define PSW_MASK_IO		0x02000000UL
+#define PSW_MASK_EXT		0x01000000UL
+#define PSW_MASK_KEY		0x00F00000UL
+#define PSW_MASK_BASE		0x00080000UL	/* always one */
+#define PSW_MASK_MCHECK		0x00040000UL
+#define PSW_MASK_WAIT		0x00020000UL
+#define PSW_MASK_PSTATE		0x00010000UL
+#define PSW_MASK_ASC		0x0000C000UL
+#define PSW_MASK_CC		0x00003000UL
+#define PSW_MASK_PM		0x00000F00UL
+#define PSW_MASK_RI		0x00000000UL
+#define PSW_MASK_EA		0x00000000UL
+#define PSW_MASK_BA		0x00000000UL
+
+#define PSW_MASK_USER		0x0000FF00UL
+
+#define PSW_ADDR_AMODE		0x80000000UL
+#define PSW_ADDR_INSN		0x7FFFFFFFUL
+
+#define PSW_DEFAULT_KEY		(((unsigned long) PAGE_DEFAULT_ACC) << 20)
+
+#define PSW_ASC_PRIMARY		0x00000000UL
+#define PSW_ASC_ACCREG		0x00004000UL
+#define PSW_ASC_SECONDARY	0x00008000UL
+#define PSW_ASC_HOME		0x0000C000UL
+
+#else /* __s390x__ */
+
+#define PSW_MASK_PER		0x4000000000000000UL
+#define PSW_MASK_DAT		0x0400000000000000UL
+#define PSW_MASK_IO		0x0200000000000000UL
+#define PSW_MASK_EXT		0x0100000000000000UL
+#define PSW_MASK_BASE		0x0000000000000000UL
+#define PSW_MASK_KEY		0x00F0000000000000UL
+#define PSW_MASK_MCHECK		0x0004000000000000UL
+#define PSW_MASK_WAIT		0x0002000000000000UL
+#define PSW_MASK_PSTATE		0x0001000000000000UL
+#define PSW_MASK_ASC		0x0000C00000000000UL
+#define PSW_MASK_CC		0x0000300000000000UL
+#define PSW_MASK_PM		0x00000F0000000000UL
+#define PSW_MASK_RI		0x0000008000000000UL
+#define PSW_MASK_EA		0x0000000100000000UL
+#define PSW_MASK_BA		0x0000000080000000UL
+
+#define PSW_MASK_USER		0x0000FF0180000000UL
+
+#define PSW_ADDR_AMODE		0x0000000000000000UL
+#define PSW_ADDR_INSN		0xFFFFFFFFFFFFFFFFUL
+
+#define PSW_DEFAULT_KEY		(((unsigned long) PAGE_DEFAULT_ACC) << 52)
+
+#define PSW_ASC_PRIMARY		0x0000000000000000UL
+#define PSW_ASC_ACCREG		0x0000400000000000UL
+#define PSW_ASC_SECONDARY	0x0000800000000000UL
+#define PSW_ASC_HOME		0x0000C00000000000UL
+
+#endif /* __s390x__ */
+
+
+/*
+ * The s390_regs structure is used to define the elf_gregset_t.
+ */
+typedef struct
+{
+	psw_t psw;
+	unsigned long gprs[NUM_GPRS];
+	unsigned int  acrs[NUM_ACRS];
+	unsigned long orig_gpr2;
+} s390_regs;
+
+/*
+ * The user_pt_regs structure exports the beginning of
+ * the in-kernel pt_regs structure to user space.
+ */
+typedef struct
+{
+	unsigned long args[1];
+	psw_t psw;
+	unsigned long gprs[NUM_GPRS];
+} user_pt_regs;
+
+/*
+ * Now for the user space program event recording (trace) definitions.
+ * The following structures are used only for the ptrace interface, don't
+ * touch or even look@it if you don't want to modify the user-space
+ * ptrace interface. In particular stay away from it for in-kernel PER.
+ */
+typedef struct
+{
+	unsigned long cr[NUM_CR_WORDS];
+} per_cr_words;
+
+#define PER_EM_MASK 0xE8000000UL
+
+typedef	struct
+{
+#ifdef __s390x__
+	unsigned                       : 32;
+#endif /* __s390x__ */
+	unsigned em_branching          : 1;
+	unsigned em_instruction_fetch  : 1;
+	/*
+	 * Switching on storage alteration automatically fixes
+	 * the storage alteration event bit in the users std.
+	 */
+	unsigned em_storage_alteration : 1;
+	unsigned em_gpr_alt_unused     : 1;
+	unsigned em_store_real_address : 1;
+	unsigned                       : 3;
+	unsigned branch_addr_ctl       : 1;
+	unsigned                       : 1;
+	unsigned storage_alt_space_ctl : 1;
+	unsigned                       : 21;
+	unsigned long starting_addr;
+	unsigned long ending_addr;
+} per_cr_bits;
+
+typedef struct
+{
+	unsigned short perc_atmid;
+	unsigned long address;
+	unsigned char access_id;
+} per_lowcore_words;
+
+typedef struct
+{
+	unsigned perc_branching          : 1;
+	unsigned perc_instruction_fetch  : 1;
+	unsigned perc_storage_alteration : 1;
+	unsigned perc_gpr_alt_unused     : 1;
+	unsigned perc_store_real_address : 1;
+	unsigned                         : 3;
+	unsigned atmid_psw_bit_31        : 1;
+	unsigned atmid_validity_bit      : 1;
+	unsigned atmid_psw_bit_32        : 1;
+	unsigned atmid_psw_bit_5         : 1;
+	unsigned atmid_psw_bit_16        : 1;
+	unsigned atmid_psw_bit_17        : 1;
+	unsigned si                      : 2;
+	unsigned long address;
+	unsigned                         : 4;
+	unsigned access_id               : 4;
+} per_lowcore_bits;
+
+typedef struct
+{
+	union {
+		per_cr_words   words;
+		per_cr_bits    bits;
+	} control_regs;
+	/*
+	 * The single_step and instruction_fetch bits are obsolete,
+	 * the kernel always sets them to zero. To enable single
+	 * stepping use ptrace(PTRACE_SINGLESTEP) instead.
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
+	unsigned long starting_addr;
+	unsigned long ending_addr;
+	union {
+		per_lowcore_words words;
+		per_lowcore_bits  bits;
+	} lowcore; 
+} per_struct;
+
+typedef struct
+{
+	unsigned int  len;
+	unsigned long kernel_addr;
+	unsigned long process_addr;
+} ptrace_area;
+
+/*
+ * S/390 specific non posix ptrace requests. I chose unusual values so
+ * they are unlikely to clash with future ptrace definitions.
+ */
+#define PTRACE_PEEKUSR_AREA           0x5000
+#define PTRACE_POKEUSR_AREA           0x5001
+#define PTRACE_PEEKTEXT_AREA	      0x5002
+#define PTRACE_PEEKDATA_AREA	      0x5003
+#define PTRACE_POKETEXT_AREA	      0x5004
+#define PTRACE_POKEDATA_AREA 	      0x5005
+#define PTRACE_GET_LAST_BREAK	      0x5006
+#define PTRACE_PEEK_SYSTEM_CALL       0x5007
+#define PTRACE_POKE_SYSTEM_CALL	      0x5008
+#define PTRACE_ENABLE_TE	      0x5009
+#define PTRACE_DISABLE_TE	      0x5010
+#define PTRACE_TE_ABORT_RAND	      0x5011
+
+/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ */
+#define PTRACE_SINGLEBLOCK	12	/* resume execution until next branch */
+
+/*
+ * PT_PROT definition is loosely based on hppa bsd definition in
+ * gdb/hppab-nat.c
+ */
+#define PTRACE_PROT                       21
+
+typedef enum
+{
+	ptprot_set_access_watchpoint,
+	ptprot_set_write_watchpoint,
+	ptprot_disable_watchpoint
+} ptprot_flags;
+
+typedef struct
+{
+	unsigned long lowaddr;
+	unsigned long hiaddr;
+	ptprot_flags prot;
+} ptprot_area;                     
+
+/* Sequence of bytes for breakpoint illegal instruction.  */
+#define S390_BREAKPOINT     {0x0,0x1}
+#define S390_BREAKPOINT_U16 ((__u16)0x0001)
+#define S390_SYSCALL_OPCODE ((__u16)0x0a00)
+#define S390_SYSCALL_SIZE   2
+
+/*
+ * The user_regs_struct defines the way the user registers are
+ * store on the stack for signal handling.
+ */
+struct user_regs_struct
+{
+	psw_t psw;
+	unsigned long gprs[NUM_GPRS];
+	unsigned int  acrs[NUM_ACRS];
+	unsigned long orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct per_info;
+	unsigned long ieee_instruction_pointer;	/* obsolete, always 0 */
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI_S390_PTRACE_H */
diff --git a/tools/include/uapi/asm-generic/bpf_perf_event.h b/tools/include/uapi/asm-generic/bpf_perf_event.h
new file mode 100644
index 0000000..53815d2
--- /dev/null
+++ b/tools/include/uapi/asm-generic/bpf_perf_event.h
@@ -0,0 +1,9 @@
+#ifndef _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
+
+#include <linux/ptrace.h>
+
+/* Export kernel pt_regs structure */
+typedef struct pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__ */
diff --git a/tools/include/uapi/linux/bpf_perf_event.h b/tools/include/uapi/linux/bpf_perf_event.h
index 0674272..8f95303 100644
--- a/tools/include/uapi/linux/bpf_perf_event.h
+++ b/tools/include/uapi/linux/bpf_perf_event.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 /* Copyright (c) 2016 Facebook
  *
  * This program is free software; you can redistribute it and/or
@@ -7,11 +8,10 @@
 #ifndef _UAPI__LINUX_BPF_PERF_EVENT_H__
 #define _UAPI__LINUX_BPF_PERF_EVENT_H__
 
-#include <linux/types.h>
-#include <linux/ptrace.h>
+#include <asm/bpf_perf_event.h>
 
 struct bpf_perf_event_data {
-	struct pt_regs regs;
+	bpf_user_pt_regs_t regs;
 	__u64 sample_period;
 };
 
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 333a486..21a2d76 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -1,7 +1,19 @@
 # SPDX-License-Identifier: GPL-2.0
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+include $(srctree)/tools/scripts/Makefile.arch
+
+$(call detected_var,SRCARCH)
+
 LIBDIR := ../../../lib
 BPFDIR := $(LIBDIR)/bpf
 APIDIR := ../../../include/uapi
+ASMDIR:= ../../../arch/$(ARCH)/include/uapi
 GENDIR := ../../../../include/generated
 GENHDR := $(GENDIR)/autoconf.h
 
@@ -9,7 +21,7 @@ ifneq ($(wildcard $(GENHDR)),)
   GENFLAGS := -DHAVE_GENHDR
 endif
 
-CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
+CFLAGS += -Wall -O2 -I$(APIDIR) -I$(ASMDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
 LDLIBS += -lcap -lelf
 
 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 3/5] arm64/bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program type
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512137948-31729-1-git-send-email-brueckner@linux.vnet.ibm.com>

Correct the broken uapi for the BPF_PROG_TYPE_PERF_EVENT program type
by exporting the user_pt_regs structure instead of the pt_regs structure
that is in-kernel only.

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
---
 arch/arm64/include/asm/perf_event.h          | 2 ++
 arch/arm64/include/uapi/asm/bpf_perf_event.h | 9 +++++++++
 2 files changed, 11 insertions(+)
 create mode 100644 arch/arm64/include/uapi/asm/bpf_perf_event.h

diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
index 8d5cbec..f9ccc36 100644
--- a/arch/arm64/include/asm/perf_event.h
+++ b/arch/arm64/include/asm/perf_event.h
@@ -18,6 +18,7 @@
 #define __ASM_PERF_EVENT_H
 
 #include <asm/stack_pointer.h>
+#include <asm/ptrace.h>
 
 #define	ARMV8_PMU_MAX_COUNTERS	32
 #define	ARMV8_PMU_COUNTER_MASK	(ARMV8_PMU_MAX_COUNTERS - 1)
@@ -79,6 +80,7 @@
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 #define perf_misc_flags(regs)	perf_misc_flags(regs)
+#define perf_arch_bpf_user_pt_regs(regs) &regs->user_regs
 #endif
 
 #define perf_arch_fetch_caller_regs(regs, __ip) { \
diff --git a/arch/arm64/include/uapi/asm/bpf_perf_event.h b/arch/arm64/include/uapi/asm/bpf_perf_event.h
new file mode 100644
index 0000000..b551b74
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/bpf_perf_event.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_BPF_PERF_EVENT_H__
+
+#include <asm/ptrace.h>
+
+typedef struct user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 2/5] s390/bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program type
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512137948-31729-1-git-send-email-brueckner@linux.vnet.ibm.com>

To mitigate and correct the broken uapi for the BPF_PROG_TYPE_PERF_EVENT
program type, introduce a user_pt_regs structure (similar to arm64) that
exports parts from the beginnig of the pt_regs structure.

The export must start with the beginning of the pt_regs structure because
to correctly calculate BPF prologues for perf (regs_query_register_offset()).

For BPF_PROG_TYPE_PERF_EVENT program types, the BPF program is then passed
a user_pt_regs structure.

Note: Depending on future changes to the s390 pt_regs structure, consider
the user_pt_regs structure to be stable for a particular kernel version
only. (Of course, s390 tries to ensure keep it stable as much as possible.)

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-and-tested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
---
 arch/s390/include/asm/perf_event.h          |  1 +
 arch/s390/include/asm/ptrace.h              | 11 ++++++++---
 arch/s390/include/uapi/asm/bpf_perf_event.h |  9 +++++++++
 arch/s390/include/uapi/asm/ptrace.h         | 11 +++++++++++
 4 files changed, 29 insertions(+), 3 deletions(-)
 create mode 100644 arch/s390/include/uapi/asm/bpf_perf_event.h

diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h
index d6c9d1e..b9c0e36 100644
--- a/arch/s390/include/asm/perf_event.h
+++ b/arch/s390/include/asm/perf_event.h
@@ -40,6 +40,7 @@ extern ssize_t cpumf_events_sysfs_show(struct device *dev,
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 #define perf_misc_flags(regs) perf_misc_flags(regs)
+#define perf_arch_bpf_user_pt_regs(regs) &regs->user_regs
 
 /* Perf pt_regs extension for sample-data-entry indicators */
 struct perf_sf_sde_regs {
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index a3788da..6f70d81 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -74,9 +74,14 @@ enum {
  */
 struct pt_regs 
 {
-	unsigned long args[1];
-	psw_t psw;
-	unsigned long gprs[NUM_GPRS];
+	union {
+		user_pt_regs user_regs;
+		struct {
+			unsigned long args[1];
+			psw_t psw;
+			unsigned long gprs[NUM_GPRS];
+		};
+	};
 	unsigned long orig_gpr2;
 	unsigned int int_code;
 	unsigned int int_parm;
diff --git a/arch/s390/include/uapi/asm/bpf_perf_event.h b/arch/s390/include/uapi/asm/bpf_perf_event.h
new file mode 100644
index 0000000..cefe7c7
--- /dev/null
+++ b/arch/s390/include/uapi/asm/bpf_perf_event.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_BPF_PERF_EVENT_H__
+
+#include <asm/ptrace.h>
+
+typedef user_pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index 0d23c8f..70f7cb2 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -291,6 +291,17 @@
 } s390_regs;
 
 /*
+ * The user_pt_regs structure exports the beginning of
+ * the in-kernel pt_regs structure to user space.
+ */
+typedef struct
+{
+	unsigned long args[1];
+	psw_t psw;
+	unsigned long gprs[NUM_GPRS];
+} user_pt_regs;
+
+/*
  * Now for the user space program event recording (trace) definitions.
  * The following structures are used only for the ptrace interface, don't
  * touch or even look at it if you don't want to modify the user-space
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 1/5] bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program type
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512137948-31729-1-git-send-email-brueckner@linux.vnet.ibm.com>

Commit 0515e5999a466dfe ("bpf: introduce BPF_PROG_TYPE_PERF_EVENT
program type") introduced the bpf_perf_event_data structure which
exports the pt_regs structure.  This is OK for multiple architectures
but fail for s390 and arm64 which do not export pt_regs.  Programs
using them, for example, the bpf selftest fail to compile on these
architectures.

For s390, exporting the pt_regs is not an option because s390 wants
to allow changes to it.  For arm64, there is a user_pt_regs structure
that covers parts of the pt_regs structure for use by user space.

To solve the broken uapi for s390 and arm64, introduce an abstract
type for pt_regs and add an asm/bpf_perf_event.h file that concretes
the type.  An asm-generic header file covers the architectures that
export pt_regs today.

The arch-specific enablement for s390 and arm64 follows in separate
commits.

Reported-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Fixes: 0515e5999a466dfe ("bpf: introduce BPF_PROG_TYPE_PERF_EVENT program type")
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-and-tested-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
---
 include/linux/perf_event.h                | 6 +++++-
 include/uapi/asm-generic/bpf_perf_event.h | 9 +++++++++
 include/uapi/linux/bpf_perf_event.h       | 5 ++---
 kernel/events/core.c                      | 2 +-
 4 files changed, 17 insertions(+), 5 deletions(-)
 create mode 100644 include/uapi/asm-generic/bpf_perf_event.h

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 2c9c87d..7546822 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -15,6 +15,7 @@
 #define _LINUX_PERF_EVENT_H
 
 #include <uapi/linux/perf_event.h>
+#include <uapi/linux/bpf_perf_event.h>
 
 /*
  * Kernel-internal data types and definitions:
@@ -787,7 +788,7 @@ struct perf_output_handle {
 };
 
 struct bpf_perf_event_data_kern {
-	struct pt_regs *regs;
+	bpf_user_pt_regs_t *regs;
 	struct perf_sample_data *data;
 	struct perf_event *event;
 };
@@ -1177,6 +1178,9 @@ extern void perf_tp_event(u16 event_type, u64 count, void *record,
 		(user_mode(regs) ? PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL)
 # define perf_instruction_pointer(regs)	instruction_pointer(regs)
 #endif
+#ifndef perf_arch_bpf_user_pt_regs
+# define perf_arch_bpf_user_pt_regs(regs) regs
+#endif
 
 static inline bool has_branch_stack(struct perf_event *event)
 {
diff --git a/include/uapi/asm-generic/bpf_perf_event.h b/include/uapi/asm-generic/bpf_perf_event.h
new file mode 100644
index 0000000..53815d2
--- /dev/null
+++ b/include/uapi/asm-generic/bpf_perf_event.h
@@ -0,0 +1,9 @@
+#ifndef _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
+#define _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
+
+#include <linux/ptrace.h>
+
+/* Export kernel pt_regs structure */
+typedef struct pt_regs bpf_user_pt_regs_t;
+
+#endif /* _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__ */
diff --git a/include/uapi/linux/bpf_perf_event.h b/include/uapi/linux/bpf_perf_event.h
index af549d4..8f95303 100644
--- a/include/uapi/linux/bpf_perf_event.h
+++ b/include/uapi/linux/bpf_perf_event.h
@@ -8,11 +8,10 @@
 #ifndef _UAPI__LINUX_BPF_PERF_EVENT_H__
 #define _UAPI__LINUX_BPF_PERF_EVENT_H__
 
-#include <linux/types.h>
-#include <linux/ptrace.h>
+#include <asm/bpf_perf_event.h>
 
 struct bpf_perf_event_data {
-	struct pt_regs regs;
+	bpf_user_pt_regs_t regs;
 	__u64 sample_period;
 };
 
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 16beab4..ba957b9 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7987,11 +7987,11 @@ static void bpf_overflow_handler(struct perf_event *event,
 {
 	struct bpf_perf_event_data_kern ctx = {
 		.data = data,
-		.regs = regs,
 		.event = event,
 	};
 	int ret = 0;
 
+	ctx.regs = perf_arch_bpf_user_pt_regs(regs);
 	preempt_disable();
 	if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
 		goto out;
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 0/5] bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program type
From: Hendrik Brueckner @ 2017-12-01 14:19 UTC (permalink / raw)
  To: linux-arm-kernel

Perf tool bpf selftests revealed a broken uapi for s390 and arm64.
With the BPF_PROG_TYPE_PERF_EVENT program type the bpf_perf_event
structure exports the pt_regs structure for all architectures.

This fails for s390 and arm64 because pt_regs are not part of the
user api and kept in-kernel only.  To mitigate the broken uapi,
introduce a wrapper that exports pt_regs in an asm-generic way.
For arm64, export the exising user_pt_regs structure.  For s390,
introduce a user_pt_regs structure that exports the beginning of
pt_regs.

Note that user_pt_regs must export from the beginning of pt_regs
as BPF_PROG_TYPE_PERF_EVENT program type is not the only type for
running BPF programs.

Some more background:
	For the bpf_perf_event, there is a uapi definition that is
	passed to the BPF program.  For other "probe" points like
	trace points, kprobes, and uprobes, there is no uapi and the
	BPF program is always passed pt_regs (which is OK as the BPF
	program runs in the kernel context).  The perf tool can attach
	BPF programs to all of these "probe" points and, optionally,
	can create a BPF prologue to access particular arguments
	(passed as registers).  For this, it uses DWARF/CFI
	information to obtain the register and calls a perf-arch
	backend function, regs_query_register_offset().  This function
	returns the index into (user_)pt_regs for a particular
	register.  Then, perf creates a BPF prologue that accesses
	this register based on the passed stucture from the "probe"
	point.

Part of this series, are also updates to the testing and bpf selftest
to deal with asm-specifics.  To complete the bpf support in perf, the
the regs_query_register_offset function is added for s390 to support
BPF prologue creation.

Hendrik Brueckner (5):
  bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program type
  s390/bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program
    type
  arm64/bpf: correct broken uapi for BPF_PROG_TYPE_PERF_EVENT program
    type
  selftests/bpf: sync kernel headers and introduce arch support in
    Makefile
  perf s390: add regs_query_register_offset()

 arch/arm64/include/asm/perf_event.h                |   2 +
 arch/arm64/include/uapi/asm/bpf_perf_event.h       |   9 +
 arch/s390/include/asm/perf_event.h                 |   1 +
 arch/s390/include/asm/ptrace.h                     |  11 +-
 arch/s390/include/uapi/asm/bpf_perf_event.h        |   9 +
 arch/s390/include/uapi/asm/ptrace.h                |  11 +
 include/linux/perf_event.h                         |   6 +-
 include/uapi/asm-generic/bpf_perf_event.h          |   9 +
 include/uapi/linux/bpf_perf_event.h                |   5 +-
 kernel/events/core.c                               |   2 +-
 tools/arch/arm64/include/uapi/asm/bpf_perf_event.h |   9 +
 tools/arch/s390/include/uapi/asm/bpf_perf_event.h  |   9 +
 tools/arch/s390/include/uapi/asm/ptrace.h          | 471 +++++++++++++++++++++
 tools/include/uapi/asm-generic/bpf_perf_event.h    |   9 +
 tools/include/uapi/linux/bpf_perf_event.h          |   6 +-
 tools/perf/arch/s390/Makefile                      |   1 +
 tools/perf/arch/s390/util/dwarf-regs.c             |  32 +-
 tools/perf/check-headers.sh                        |   1 +
 tools/testing/selftests/bpf/Makefile               |  14 +-
 19 files changed, 602 insertions(+), 15 deletions(-)
 create mode 100644 arch/arm64/include/uapi/asm/bpf_perf_event.h
 create mode 100644 arch/s390/include/uapi/asm/bpf_perf_event.h
 create mode 100644 include/uapi/asm-generic/bpf_perf_event.h
 create mode 100644 tools/arch/arm64/include/uapi/asm/bpf_perf_event.h
 create mode 100644 tools/arch/s390/include/uapi/asm/bpf_perf_event.h
 create mode 100644 tools/arch/s390/include/uapi/asm/ptrace.h
 create mode 100644 tools/include/uapi/asm-generic/bpf_perf_event.h

-- 
1.8.3.1

^ permalink raw reply

* [PATCH RT] arm*: disable NEON in kernel mode
From: Mark Rutland @ 2017-12-01 14:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171201134506.GF1612@linutronix.de>

[Adding Ard, who wrote the NEON crypto code]

On Fri, Dec 01, 2017 at 02:45:06PM +0100, Sebastian Andrzej Siewior wrote:
> +arm folks, to let you know
> 
> On 2017-12-01 11:43:32 [+0100], To linux-rt-users at vger.kernel.org wrote:
> > NEON in kernel mode is used by the crypto algorithms and raid6 code.
> > While the raid6 code looks okay, the crypto algorithms do not: NEON
> > is enabled on first invocation and may allocate/free/map memory before
> > the NEON mode is disabled again.

Could you elaborate on why this is a problem?

I guess this is because kernel_neon_{begin,end}() disable preemption?

... is this specific to RT?

Thanks,
Mark.

> > This needs to be changed until it can be enabled.
> > On ARM NEON in kernel mode can be simply disabled. on ARM64 it needs to
> > stay on due to possible EFI callbacks so here I disable each algorithm.
> > 
> > Cc: stable-rt at vger.kernel.org
> > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> > ---
> >  arch/arm/Kconfig                  |  2 +-
> >  arch/arm64/crypto/Kconfig         | 20 ++++++++++----------
> >  arch/arm64/crypto/crc32-ce-glue.c |  3 ++-
> >  3 files changed, 13 insertions(+), 12 deletions(-)
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index d1346a160760..914fecb088a8 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -2164,7 +2164,7 @@ config NEON
> >  
> >  config KERNEL_MODE_NEON
> >  	bool "Support for NEON in kernel mode"
> > -	depends on NEON && AEABI
> > +	depends on NEON && AEABI && !PREEMPT_RT_BASE
> >  	help
> >  	  Say Y to include support for NEON in kernel mode.
> >  
> > diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
> > index 70c517aa4501..2a5f05b5a19a 100644
> > --- a/arch/arm64/crypto/Kconfig
> > +++ b/arch/arm64/crypto/Kconfig
> > @@ -19,19 +19,19 @@ config CRYPTO_SHA512_ARM64
> >  
> >  config CRYPTO_SHA1_ARM64_CE
> >  	tristate "SHA-1 digest algorithm (ARMv8 Crypto Extensions)"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_HASH
> >  	select CRYPTO_SHA1
> >  
> >  config CRYPTO_SHA2_ARM64_CE
> >  	tristate "SHA-224/SHA-256 digest algorithm (ARMv8 Crypto Extensions)"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_HASH
> >  	select CRYPTO_SHA256_ARM64
> >  
> >  config CRYPTO_GHASH_ARM64_CE
> >  	tristate "GHASH/AES-GCM using ARMv8 Crypto Extensions"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_HASH
> >  	select CRYPTO_GF128MUL
> >  	select CRYPTO_AES
> > @@ -39,7 +39,7 @@ config CRYPTO_GHASH_ARM64_CE
> >  
> >  config CRYPTO_CRCT10DIF_ARM64_CE
> >  	tristate "CRCT10DIF digest algorithm using PMULL instructions"
> > -	depends on KERNEL_MODE_NEON && CRC_T10DIF
> > +	depends on KERNEL_MODE_NEON && CRC_T10DIF && !PREEMPT_RT_BASE
> >  	select CRYPTO_HASH
> >  
> >  config CRYPTO_CRC32_ARM64_CE
> > @@ -53,13 +53,13 @@ config CRYPTO_AES_ARM64
> >  
> >  config CRYPTO_AES_ARM64_CE
> >  	tristate "AES core cipher using ARMv8 Crypto Extensions"
> > -	depends on ARM64 && KERNEL_MODE_NEON
> > +	depends on ARM64 && KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_ALGAPI
> >  	select CRYPTO_AES_ARM64
> >  
> >  config CRYPTO_AES_ARM64_CE_CCM
> >  	tristate "AES in CCM mode using ARMv8 Crypto Extensions"
> > -	depends on ARM64 && KERNEL_MODE_NEON
> > +	depends on ARM64 && KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_ALGAPI
> >  	select CRYPTO_AES_ARM64_CE
> >  	select CRYPTO_AES_ARM64
> > @@ -67,7 +67,7 @@ config CRYPTO_AES_ARM64_CE_CCM
> >  
> >  config CRYPTO_AES_ARM64_CE_BLK
> >  	tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_BLKCIPHER
> >  	select CRYPTO_AES_ARM64_CE
> >  	select CRYPTO_AES_ARM64
> > @@ -75,7 +75,7 @@ config CRYPTO_AES_ARM64_CE_BLK
> >  
> >  config CRYPTO_AES_ARM64_NEON_BLK
> >  	tristate "AES in ECB/CBC/CTR/XTS modes using NEON instructions"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_BLKCIPHER
> >  	select CRYPTO_AES_ARM64
> >  	select CRYPTO_AES
> > @@ -83,13 +83,13 @@ config CRYPTO_AES_ARM64_NEON_BLK
> >  
> >  config CRYPTO_CHACHA20_NEON
> >  	tristate "NEON accelerated ChaCha20 symmetric cipher"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_BLKCIPHER
> >  	select CRYPTO_CHACHA20
> >  
> >  config CRYPTO_AES_ARM64_BS
> >  	tristate "AES in ECB/CBC/CTR/XTS modes using bit-sliced NEON algorithm"
> > -	depends on KERNEL_MODE_NEON
> > +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
> >  	select CRYPTO_BLKCIPHER
> >  	select CRYPTO_AES_ARM64_NEON_BLK
> >  	select CRYPTO_AES_ARM64
> > diff --git a/arch/arm64/crypto/crc32-ce-glue.c b/arch/arm64/crypto/crc32-ce-glue.c
> > index 624f4137918c..599de95cd86d 100644
> > --- a/arch/arm64/crypto/crc32-ce-glue.c
> > +++ b/arch/arm64/crypto/crc32-ce-glue.c
> > @@ -206,7 +206,8 @@ static struct shash_alg crc32_pmull_algs[] = { {
> >  
> >  static int __init crc32_pmull_mod_init(void)
> >  {
> > -	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_PMULL)) {
> > +	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
> > +	    !IS_ENABLED(CONFIG_PREEMPT_RT_BASE) && (elf_hwcap & HWCAP_PMULL)) {
> >  		crc32_pmull_algs[0].update = crc32_pmull_update;
> >  		crc32_pmull_algs[1].update = crc32c_pmull_update;
> >  
> > -- 
> > 2.15.0
> 
> _______________________________________________
> 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 v2 00/18] arm64: Unmap the kernel whilst running in userspace (KAISER)
From: Mark Rutland @ 2017-12-01 14:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512059986-21325-1-git-send-email-will.deacon@arm.com>

Hi Will,

On Thu, Nov 30, 2017 at 04:39:28PM +0000, Will Deacon wrote:
> Hi again,
> 
> This is version two of the patches previously posted here:
> 
>   http://lists.infradead.org/pipermail/linux-arm-kernel/2017-November/542751.html
> 
> Changes since v1 include:
> 
>   * Based on v4.15-rc1
>   * Trampoline moved into FIXMAP area
>   * Explicit static key replaced by cpu cap
>   * Disable SPE for userspace profiling if kernel unmapped at EL0
>   * Changed polarity of cpu feature to match config option
>   * Changed command-line option so we can force on in future if necessary
>   * Changed Falkor workaround to invalidate different page within 2MB region
>   * Reworked alternative sequences in entry.S, since the NOP slides with
>     kaiser=off were measurable

This generally looks good to me.

For patches patches 1-10, 13-15, and 17, feel free to add:

Reviewed-by: Mark Rutland <mark.rutland@arm.com>

(assuming you fix up the issue Robin spotted on patch 14).

Thanks,
Mark.

^ permalink raw reply

* [PATCH v2 16/18] arm64: entry: Add fake CPU feature for unmapping the kernel at EL0
From: Mark Rutland @ 2017-12-01 13:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512059986-21325-17-git-send-email-will.deacon@arm.com>

On Thu, Nov 30, 2017 at 04:39:44PM +0000, Will Deacon wrote:
> -#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
> -	eret
> -#else
>  	.if	\el == 0
> +alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0

Since we patch this eret ...

> +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> +alternative_if ARM64_UNMAP_KERNEL_AT_EL0
>  	bne	4f
>  	msr	far_el1, x30
>  	tramp_alias	x30, tramp_exit_native
> @@ -334,10 +336,11 @@ alternative_else_nop_endif
>  4:
>  	tramp_alias	x30, tramp_exit_compat
>  	br	x30
> +alternative_else_nop_endif
> +#endif

... we don't need the alternative here. This code won't be executed when
not needed, and the alternative just bloats the kernel.

We can/should keep the ifdef, though.

Thanks,
Mark.

^ permalink raw reply

* [PATCH v2 13/18] arm64: entry: Hook up entry trampoline to exception vectors
From: Mark Rutland @ 2017-12-01 13:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512059986-21325-14-git-send-email-will.deacon@arm.com>

On Thu, Nov 30, 2017 at 04:39:41PM +0000, Will Deacon wrote:
>  	.macro kernel_ventry, el, label, regsize = 64
>  	.align 7
> +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> +	.if	\el == 0
> +	.if	\regsize == 64
> +	mrs	x30, tpidrro_el0
> +	msr	tpidrro_el0, xzr
> +	.else
> +	mov	x30, xzr

I guess that's just to prevent acccidental leaks if we dump registers
somewhere, since we used x30 as a scratch register?

> +	.macro tramp_alias, dst, sym
> +	mov_q	\dst, TRAMP_VALIAS
> +	add	\dst, \dst, #(\sym - .entry.tramp.text)
> +	.endm

I didn't realise you could refer to sections like this; neat!

Otherwise, looks fine to me.

Thanks,
Mark.

^ permalink raw reply

* [PATCH V4 2/5] ACPI / bus: Introduce acpi_get_match_data() function
From: Rafael J. Wysocki @ 2017-12-01 13:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512096776-22883-3-git-send-email-okaya@codeaurora.org>

On Friday, December 1, 2017 3:52:53 AM CET Sinan Kaya wrote:
> OF has of_device_get_match_data() function to extract driver specific data
> structure. Add a similar function for ACPI.
> 
> Signed-off-by: Sinan Kaya <okaya@codeaurora.org>

Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

> ---
>  drivers/acpi/bus.c   | 12 ++++++++++++
>  include/linux/acpi.h |  6 ++++++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
> index 4d0979e..b271eb1 100644
> --- a/drivers/acpi/bus.c
> +++ b/drivers/acpi/bus.c
> @@ -785,6 +785,18 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
>  }
>  EXPORT_SYMBOL_GPL(acpi_match_device);
>  
> +void *acpi_get_match_data(const struct device *dev)
> +{
> +	const struct acpi_device_id *match;
> +
> +	match = acpi_match_device(dev->driver->acpi_match_table, dev);
> +	if (!match)
> +		return NULL;
> +
> +	return (void *)match->driver_data;
> +}
> +EXPORT_SYMBOL_GPL(acpi_get_match_data);
> +
>  int acpi_match_device_ids(struct acpi_device *device,
>  			  const struct acpi_device_id *ids)
>  {
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 502af53..a927260 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -584,6 +584,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
>  const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
>  					       const struct device *dev);
>  
> +void *acpi_get_match_data(const struct device *dev);
>  extern bool acpi_driver_match_device(struct device *dev,
>  				     const struct device_driver *drv);
>  int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
> @@ -755,6 +756,11 @@ static inline const struct acpi_device_id *acpi_match_device(
>  	return NULL;
>  }
>  
> +static inline void *acpi_get_match_data(const struct device *dev)
> +{
> +	return NULL;
> +}
> +
>  static inline bool acpi_driver_match_device(struct device *dev,
>  					    const struct device_driver *drv)
>  {
> 

^ permalink raw reply

* [PATCH net-next v4 2/2] net: ethernet: socionext: add AVE ethernet driver
From: Andrew Lunn @ 2017-12-01 13:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512090230-27594-3-git-send-email-hayashi.kunihiko@socionext.com>

On Fri, Dec 01, 2017 at 10:03:50AM +0900, Kunihiko Hayashi wrote:
> The UniPhier platform from Socionext provides the AVE ethernet
> controller that includes MAC and MDIO bus supporting RGMII/RMII
> modes. The controller is named AVE.
> 
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>

Hi Kunihiko

I reviewed the PHY and MDIO code. It all looks good. I cannot say much
about the rest of it though.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* [PATCH RT] arm*: disable NEON in kernel mode
From: Sebastian Andrzej Siewior @ 2017-12-01 13:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171201104331.GB1612@linutronix.de>

+arm folks, to let you know

On 2017-12-01 11:43:32 [+0100], To linux-rt-users at vger.kernel.org wrote:
> NEON in kernel mode is used by the crypto algorithms and raid6 code.
> While the raid6 code looks okay, the crypto algorithms do not: NEON
> is enabled on first invocation and may allocate/free/map memory before
> the NEON mode is disabled again.
> This needs to be changed until it can be enabled.
> On ARM NEON in kernel mode can be simply disabled. on ARM64 it needs to
> stay on due to possible EFI callbacks so here I disable each algorithm.
> 
> Cc: stable-rt at vger.kernel.org
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
>  arch/arm/Kconfig                  |  2 +-
>  arch/arm64/crypto/Kconfig         | 20 ++++++++++----------
>  arch/arm64/crypto/crc32-ce-glue.c |  3 ++-
>  3 files changed, 13 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index d1346a160760..914fecb088a8 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -2164,7 +2164,7 @@ config NEON
>  
>  config KERNEL_MODE_NEON
>  	bool "Support for NEON in kernel mode"
> -	depends on NEON && AEABI
> +	depends on NEON && AEABI && !PREEMPT_RT_BASE
>  	help
>  	  Say Y to include support for NEON in kernel mode.
>  
> diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
> index 70c517aa4501..2a5f05b5a19a 100644
> --- a/arch/arm64/crypto/Kconfig
> +++ b/arch/arm64/crypto/Kconfig
> @@ -19,19 +19,19 @@ config CRYPTO_SHA512_ARM64
>  
>  config CRYPTO_SHA1_ARM64_CE
>  	tristate "SHA-1 digest algorithm (ARMv8 Crypto Extensions)"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_HASH
>  	select CRYPTO_SHA1
>  
>  config CRYPTO_SHA2_ARM64_CE
>  	tristate "SHA-224/SHA-256 digest algorithm (ARMv8 Crypto Extensions)"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_HASH
>  	select CRYPTO_SHA256_ARM64
>  
>  config CRYPTO_GHASH_ARM64_CE
>  	tristate "GHASH/AES-GCM using ARMv8 Crypto Extensions"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_HASH
>  	select CRYPTO_GF128MUL
>  	select CRYPTO_AES
> @@ -39,7 +39,7 @@ config CRYPTO_GHASH_ARM64_CE
>  
>  config CRYPTO_CRCT10DIF_ARM64_CE
>  	tristate "CRCT10DIF digest algorithm using PMULL instructions"
> -	depends on KERNEL_MODE_NEON && CRC_T10DIF
> +	depends on KERNEL_MODE_NEON && CRC_T10DIF && !PREEMPT_RT_BASE
>  	select CRYPTO_HASH
>  
>  config CRYPTO_CRC32_ARM64_CE
> @@ -53,13 +53,13 @@ config CRYPTO_AES_ARM64
>  
>  config CRYPTO_AES_ARM64_CE
>  	tristate "AES core cipher using ARMv8 Crypto Extensions"
> -	depends on ARM64 && KERNEL_MODE_NEON
> +	depends on ARM64 && KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_ALGAPI
>  	select CRYPTO_AES_ARM64
>  
>  config CRYPTO_AES_ARM64_CE_CCM
>  	tristate "AES in CCM mode using ARMv8 Crypto Extensions"
> -	depends on ARM64 && KERNEL_MODE_NEON
> +	depends on ARM64 && KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_ALGAPI
>  	select CRYPTO_AES_ARM64_CE
>  	select CRYPTO_AES_ARM64
> @@ -67,7 +67,7 @@ config CRYPTO_AES_ARM64_CE_CCM
>  
>  config CRYPTO_AES_ARM64_CE_BLK
>  	tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_BLKCIPHER
>  	select CRYPTO_AES_ARM64_CE
>  	select CRYPTO_AES_ARM64
> @@ -75,7 +75,7 @@ config CRYPTO_AES_ARM64_CE_BLK
>  
>  config CRYPTO_AES_ARM64_NEON_BLK
>  	tristate "AES in ECB/CBC/CTR/XTS modes using NEON instructions"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_BLKCIPHER
>  	select CRYPTO_AES_ARM64
>  	select CRYPTO_AES
> @@ -83,13 +83,13 @@ config CRYPTO_AES_ARM64_NEON_BLK
>  
>  config CRYPTO_CHACHA20_NEON
>  	tristate "NEON accelerated ChaCha20 symmetric cipher"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_BLKCIPHER
>  	select CRYPTO_CHACHA20
>  
>  config CRYPTO_AES_ARM64_BS
>  	tristate "AES in ECB/CBC/CTR/XTS modes using bit-sliced NEON algorithm"
> -	depends on KERNEL_MODE_NEON
> +	depends on KERNEL_MODE_NEON && !PREEMPT_RT_BASE
>  	select CRYPTO_BLKCIPHER
>  	select CRYPTO_AES_ARM64_NEON_BLK
>  	select CRYPTO_AES_ARM64
> diff --git a/arch/arm64/crypto/crc32-ce-glue.c b/arch/arm64/crypto/crc32-ce-glue.c
> index 624f4137918c..599de95cd86d 100644
> --- a/arch/arm64/crypto/crc32-ce-glue.c
> +++ b/arch/arm64/crypto/crc32-ce-glue.c
> @@ -206,7 +206,8 @@ static struct shash_alg crc32_pmull_algs[] = { {
>  
>  static int __init crc32_pmull_mod_init(void)
>  {
> -	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_PMULL)) {
> +	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
> +	    !IS_ENABLED(CONFIG_PREEMPT_RT_BASE) && (elf_hwcap & HWCAP_PMULL)) {
>  		crc32_pmull_algs[0].update = crc32_pmull_update;
>  		crc32_pmull_algs[1].update = crc32c_pmull_update;
>  
> -- 
> 2.15.0

^ permalink raw reply

* [PATCH v4 10/10] ARM: dtsi: axp81x: set pinmux for GPIO0/1 when used as LDOs
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

On AXP813/818, GPIO0 and GPIO1 can be used as LDO as (respectively)
ldo_io0 and ldo_io1.

Let's add the pinctrl properties to the said regulators.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
 arch/arm/boot/dts/axp81x.dtsi | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/axp81x.dtsi b/arch/arm/boot/dts/axp81x.dtsi
index 0ef959d..fd55b89 100644
--- a/arch/arm/boot/dts/axp81x.dtsi
+++ b/arch/arm/boot/dts/axp81x.dtsi
@@ -52,6 +52,16 @@
 		compatible = "x-powers,axp813-gpio";
 		gpio-controller;
 		#gpio-cells = <2>;
+
+		gpio0_ldo: gpio0-ldo {
+			pins = "GPIO0";
+			function = "ldo";
+		};
+
+		gpio1_ldo: gpio1-ldo {
+			pins = "GPIO1";
+			function = "ldo";
+		};
 	};
 
 	regulators {
@@ -119,11 +129,15 @@
 		};
 
 		reg_ldo_io0: ldo-io0 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&gpio0_ldo>;
 			/* Disable by default to avoid conflicts with GPIO */
 			status = "disabled";
 		};
 
 		reg_ldo_io1: ldo-io1 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&gpio1_ldo>;
 			/* Disable by default to avoid conflicts with GPIO */
 			status = "disabled";
 		};
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 09/10] ARM: dtsi: axp81x: add GPIO DT node
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

This adds DT node for the GPIO/pinctrl part present in AXP813/AXP818.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
 arch/arm/boot/dts/axp81x.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/axp81x.dtsi b/arch/arm/boot/dts/axp81x.dtsi
index 73b761f..0ef959d 100644
--- a/arch/arm/boot/dts/axp81x.dtsi
+++ b/arch/arm/boot/dts/axp81x.dtsi
@@ -48,6 +48,12 @@
 	interrupt-controller;
 	#interrupt-cells = <1>;
 
+	axp_gpio: axp-gpio {
+		compatible = "x-powers,axp813-gpio";
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
 	regulators {
 		/* Default work frequency for buck regulators */
 		x-powers,dcdc-freq = <3000>;
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 08/10] mfd: axp20x: add pinctrl cell for AXP813
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

As GPIO/pinctrl driver now supports AXP813, add a cell for it.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/mfd/axp20x.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 2468b43..d8c92fb 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -878,6 +878,9 @@ static struct mfd_cell axp813_cells[] = {
 		.resources		= axp803_pek_resources,
 	}, {
 		.name			= "axp20x-regulator",
+	}, {
+		.name			= "axp20x-gpio",
+		.of_compatible		= "x-powers,axp813-gpio",
 	}
 };
 
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 07/10] pinctrl: axp209: add support for AXP813 GPIOs
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

The AXP813 has only two GPIOs. GPIO0 can either be used as a GPIO, an
LDO regulator or an ADC. GPIO1 can be used either as a GPIO or an LDO
regulator.

Moreover, the status bit of the GPIOs when in input mode is not offset
by 4 unlike the AXP209.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/gpio/gpio-axp209.txt | 13 +++-
 drivers/pinctrl/pinctrl-axp209.c                       | 35 ++++++++---
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
index 4705020..1bbf7ab 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
@@ -4,7 +4,9 @@ This driver follows the usual GPIO bindings found in
 Documentation/devicetree/bindings/gpio/gpio.txt
 
 Required properties:
-- compatible: Should be "x-powers,axp209-gpio"
+- compatible: Should be one of:
+	- "x-powers,axp209-gpio"
+	- "x-powers,axp813-gpio"
 - #gpio-cells: Should be two. The first cell is the pin number and the
   second is the GPIO flags.
 - gpio-controller: Marks the device node as a GPIO controller.
@@ -49,8 +51,17 @@ Example:
 GPIOs and their functions
 -------------------------
 
+axp209
+------
 GPIO	|	Functions
 ------------------------
 GPIO0	|	gpio_in, gpio_out, ldo, adc
 GPIO1	|	gpio_in, gpio_out, ldo, adc
 GPIO2	|	gpio_in, gpio_out
+
+axp813
+------
+GPIO	|	Functions
+------------------------
+GPIO0	|	gpio_in, gpio_out, ldo, adc
+GPIO1	|	gpio_in, gpio_out, ldo
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 504e96c..5f1278f 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -19,6 +19,7 @@
 #include <linux/mfd/axp20x.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
@@ -41,6 +42,8 @@
 #define AXP20X_MUX_GPIO_IN		BIT(1)
 #define AXP20X_MUX_ADC			BIT(2)
 
+#define AXP813_MUX_ADC			(BIT(2) | BIT(0))
+
 struct axp20x_pctrl_desc {
 	const struct pinctrl_pin_desc	*pins;
 	unsigned int			npins;
@@ -74,6 +77,11 @@ static const struct pinctrl_pin_desc axp209_pins[] = {
 	PINCTRL_PIN(2, "GPIO2"),
 };
 
+static const struct pinctrl_pin_desc axp813_pins[] = {
+	PINCTRL_PIN(0, "GPIO0"),
+	PINCTRL_PIN(1, "GPIO1"),
+};
+
 static const struct axp20x_pctrl_desc axp20x_data = {
 	.pins	= axp209_pins,
 	.npins	= ARRAY_SIZE(axp209_pins),
@@ -83,6 +91,15 @@ static const struct axp20x_pctrl_desc axp20x_data = {
 	.adc_mux = AXP20X_MUX_ADC,
 };
 
+static const struct axp20x_pctrl_desc axp813_data = {
+	.pins	= axp813_pins,
+	.npins	= ARRAY_SIZE(axp813_pins),
+	.ldo_mask = BIT(0) | BIT(1),
+	.adc_mask = BIT(0),
+	.gpio_status_offset = 0,
+	.adc_mux = AXP813_MUX_ADC,
+};
+
 static int axp20x_gpio_get_reg(unsigned offset)
 {
 	switch (offset) {
@@ -358,10 +375,18 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev)
 				      pctl->desc->pins);
 }
 
+static const struct of_device_id axp20x_pctl_match[] = {
+	{ .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, },
+	{ .compatible = "x-powers,axp813-gpio", .data = &axp813_data, },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
+
 static int axp20x_pctl_probe(struct platform_device *pdev)
 {
 	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 	struct axp20x_pctl *pctl;
+	struct device *dev = &pdev->dev;
 	struct pinctrl_desc *pctrl_desc;
 	int ret;
 
@@ -389,9 +414,9 @@ static int axp20x_pctl_probe(struct platform_device *pdev)
 	pctl->chip.set			= axp20x_gpio_set;
 	pctl->chip.direction_input	= axp20x_gpio_input;
 	pctl->chip.direction_output	= axp20x_gpio_output;
-	pctl->chip.ngpio		= 3;
+	pctl->chip.ngpio		= pctl->desc->npins;
 
-	pctl->desc = &axp20x_data;
+	pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev);
 	pctl->regmap = axp20x->regmap;
 	pctl->dev = &pdev->dev;
 
@@ -436,12 +461,6 @@ static int axp20x_pctl_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id axp20x_pctl_match[] = {
-	{ .compatible = "x-powers,axp209-gpio" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
-
 static struct platform_driver axp20x_pctl_driver = {
 	.probe		= axp20x_pctl_probe,
 	.driver = {
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 06/10] pinctrl: axp209: add programmable ADC muxing value
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

To prepare for patches that will add support for a new PMIC that has a
different GPIO adc muxing value, add an adc_mux within axp20x_pctl
structure and use it.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
 drivers/pinctrl/pinctrl-axp209.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 3fae81f..504e96c 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -49,6 +49,7 @@ struct axp20x_pctrl_desc {
 	/* Stores the pins supporting ADC function. Bit offset is pin number. */
 	u8				adc_mask;
 	u8				gpio_status_offset;
+	u8				adc_mux;
 };
 
 struct axp20x_pinctrl_function {
@@ -79,6 +80,7 @@ static const struct axp20x_pctrl_desc axp20x_data = {
 	.ldo_mask = BIT(0) | BIT(1),
 	.adc_mask = BIT(0) | BIT(1),
 	.gpio_status_offset = 4,
+	.adc_mux = AXP20X_MUX_ADC,
 };
 
 static int axp20x_gpio_get_reg(unsigned offset)
@@ -333,7 +335,7 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev)
 	 * See comment in axp20x_pmx_set_mux.
 	 */
 	pctl->funcs[AXP20X_FUNC_ADC].name = "adc";
-	pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+	pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux;
 
 	/* Every pin supports GPIO_OUT and GPIO_IN functions */
 	for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 05/10] pinctrl: axp209: add programmable gpio_status_offset
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

To prepare for patches that will add support for a new PMIC that has a
different GPIO input status register, add a gpio_status_offset within
axp20x_pctl structure and use it.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
---
 drivers/pinctrl/pinctrl-axp209.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 6201d2b..3fae81f 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -48,6 +48,7 @@ struct axp20x_pctrl_desc {
 	u8				ldo_mask;
 	/* Stores the pins supporting ADC function. Bit offset is pin number. */
 	u8				adc_mask;
+	u8				gpio_status_offset;
 };
 
 struct axp20x_pinctrl_function {
@@ -77,6 +78,7 @@ static const struct axp20x_pctrl_desc axp20x_data = {
 	.npins	= ARRAY_SIZE(axp209_pins),
 	.ldo_mask = BIT(0) | BIT(1),
 	.adc_mask = BIT(0) | BIT(1),
+	.gpio_status_offset = 4,
 };
 
 static int axp20x_gpio_get_reg(unsigned offset)
@@ -108,7 +110,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
 	if (ret)
 		return ret;
 
-	return !!(val & BIT(offset + 4));
+	return !!(val & BIT(offset + pctl->desc->gpio_status_offset));
 }
 
 static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 04/10] pinctrl: axp209: rename everything from gpio to pctl
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

This driver used to do only GPIO features of the GPIOs in X-Powers
AXP20X. Now that we have migrated everything to the pinctrl subsystem
and added pinctrl features, rename everything related to pinctrl from
gpio to pctl to ease the understanding of differences between GPIO
and pinctrl features.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
 drivers/pinctrl/pinctrl-axp209.c | 180 ++++++++++++++++----------------
 1 file changed, 90 insertions(+), 90 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 2dc286f..6201d2b 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -57,7 +57,7 @@ struct axp20x_pinctrl_function {
 	unsigned int	ngroups;
 };
 
-struct axp20x_gpio {
+struct axp20x_pctl {
 	struct gpio_chip	chip;
 	struct regmap		*regmap;
 	struct pinctrl_dev			*pctl_dev;
@@ -100,11 +100,11 @@ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
 
 static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	struct axp20x_pctl *pctl = gpiochip_get_data(chip);
 	unsigned int val;
 	int ret;
 
-	ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
+	ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val);
 	if (ret)
 		return ret;
 
@@ -113,7 +113,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
 
 static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	struct axp20x_pctl *pctl = gpiochip_get_data(chip);
 	unsigned int val;
 	int reg, ret;
 
@@ -121,7 +121,7 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 	if (reg < 0)
 		return reg;
 
-	ret = regmap_read(gpio->regmap, reg, &val);
+	ret = regmap_read(pctl->regmap, reg, &val);
 	if (ret)
 		return ret;
 
@@ -151,14 +151,14 @@ static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
 static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
 			    int value)
 {
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	struct axp20x_pctl *pctl = gpiochip_get_data(chip);
 	int reg;
 
 	reg = axp20x_gpio_get_reg(offset);
 	if (reg < 0)
 		return;
 
-	regmap_update_bits(gpio->regmap, reg,
+	regmap_update_bits(pctl->regmap, reg,
 			   AXP20X_GPIO_FUNCTIONS,
 			   value ? AXP20X_GPIO_FUNCTION_OUT_HIGH :
 			   AXP20X_GPIO_FUNCTION_OUT_LOW);
@@ -167,30 +167,30 @@ static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
 static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset,
 			  u8 config)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 	int reg;
 
 	reg = axp20x_gpio_get_reg(offset);
 	if (reg < 0)
 		return reg;
 
-	return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS,
+	return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS,
 				  config);
 }
 
 static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	return ARRAY_SIZE(gpio->funcs);
+	return ARRAY_SIZE(pctl->funcs);
 }
 
 static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev,
 					unsigned int selector)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	return gpio->funcs[selector].name;
+	return pctl->funcs[selector].name;
 }
 
 static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
@@ -198,10 +198,10 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
 				  const char * const **groups,
 				  unsigned int *num_groups)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	*groups = gpio->funcs[selector].groups;
-	*num_groups = gpio->funcs[selector].ngroups;
+	*groups = pctl->funcs[selector].groups;
+	*num_groups = pctl->funcs[selector].ngroups;
 
 	return 0;
 }
@@ -209,18 +209,18 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
 static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
 			      unsigned int function, unsigned int group)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 	unsigned int mask;
 
 	/* Every pin supports GPIO_OUT and GPIO_IN functions */
 	if (function <= AXP20X_FUNC_GPIO_IN)
 		return axp20x_pmx_set(pctldev, group,
-				      gpio->funcs[function].muxval);
+				      pctl->funcs[function].muxval);
 
 	if (function == AXP20X_FUNC_LDO)
-		mask = gpio->desc->ldo_mask;
+		mask = pctl->desc->ldo_mask;
 	else
-		mask = gpio->desc->adc_mask;
+		mask = pctl->desc->adc_mask;
 
 	if (!(BIT(group) & mask))
 		return -EINVAL;
@@ -234,21 +234,21 @@ static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
 	if (function == AXP20X_FUNC_LDO)
 		return 0;
 
-	return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval);
+	return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval);
 }
 
 static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 					 struct pinctrl_gpio_range *range,
 					 unsigned int offset, bool input)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
 	if (input)
 		return axp20x_pmx_set(pctldev, offset,
-				      gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval);
+				      pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval);
 
 	return axp20x_pmx_set(pctldev, offset,
-			      gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
+			      pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
 }
 
 static const struct pinmux_ops axp20x_pmx_ops = {
@@ -262,17 +262,17 @@ static const struct pinmux_ops axp20x_pmx_ops = {
 
 static int axp20x_groups_cnt(struct pinctrl_dev *pctldev)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	return gpio->desc->npins;
+	return pctl->desc->npins;
 }
 
 static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
 			     const unsigned int **pins, unsigned int *num_pins)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	*pins = (unsigned int *)&gpio->desc->pins[selector];
+	*pins = (unsigned int *)&pctl->desc->pins[selector];
 	*num_pins = 1;
 
 	return 0;
@@ -281,9 +281,9 @@ static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
 static const char *axp20x_group_name(struct pinctrl_dev *pctldev,
 				     unsigned int selector)
 {
-	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev);
 
-	return gpio->desc->pins[selector].name;
+	return pctl->desc->pins[selector].name;
 }
 
 static const struct pinctrl_ops axp20x_pctrl_ops = {
@@ -318,46 +318,46 @@ static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask,
 
 static void axp20x_build_funcs_groups(struct platform_device *pdev)
 {
-	struct axp20x_gpio *gpio = platform_get_drvdata(pdev);
+	struct axp20x_pctl *pctl = platform_get_drvdata(pdev);
 	int i, pin;
 
-	gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
-	gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
-	gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
-	gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
-	gpio->funcs[AXP20X_FUNC_LDO].name = "ldo";
+	pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
+	pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
+	pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
+	pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
+	pctl->funcs[AXP20X_FUNC_LDO].name = "ldo";
 	/*
 	 * Muxval for LDO is useless as we won't use it.
 	 * See comment in axp20x_pmx_set_mux.
 	 */
-	gpio->funcs[AXP20X_FUNC_ADC].name = "adc";
-	gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+	pctl->funcs[AXP20X_FUNC_ADC].name = "adc";
+	pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
 
 	/* Every pin supports GPIO_OUT and GPIO_IN functions */
 	for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
-		gpio->funcs[i].ngroups = gpio->desc->npins;
-		gpio->funcs[i].groups = devm_kzalloc(&pdev->dev,
-						     gpio->desc->npins * sizeof(const char *),
+		pctl->funcs[i].ngroups = pctl->desc->npins;
+		pctl->funcs[i].groups = devm_kzalloc(&pdev->dev,
+						     pctl->desc->npins * sizeof(const char *),
 						     GFP_KERNEL);
-		for (pin = 0; pin < gpio->desc->npins; pin++)
-			gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name;
+		for (pin = 0; pin < pctl->desc->npins; pin++)
+			pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name;
 	}
 
-	axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask,
-				      gpio->desc->npins,
-				      &gpio->funcs[AXP20X_FUNC_LDO],
-				      gpio->desc->pins);
+	axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask,
+				      pctl->desc->npins,
+				      &pctl->funcs[AXP20X_FUNC_LDO],
+				      pctl->desc->pins);
 
-	axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask,
-				      gpio->desc->npins,
-				      &gpio->funcs[AXP20X_FUNC_ADC],
-				      gpio->desc->pins);
+	axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask,
+				      pctl->desc->npins,
+				      &pctl->funcs[AXP20X_FUNC_ADC],
+				      pctl->desc->pins);
 }
 
-static int axp20x_gpio_probe(struct platform_device *pdev)
+static int axp20x_pctl_probe(struct platform_device *pdev)
 {
 	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
-	struct axp20x_gpio *gpio;
+	struct axp20x_pctl *pctl;
 	struct pinctrl_desc *pctrl_desc;
 	int ret;
 
@@ -369,29 +369,29 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
-	if (!gpio)
+	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+	if (!pctl)
 		return -ENOMEM;
 
-	gpio->chip.base			= -1;
-	gpio->chip.can_sleep		= true;
-	gpio->chip.request		= gpiochip_generic_request;
-	gpio->chip.free			= gpiochip_generic_free;
-	gpio->chip.parent		= &pdev->dev;
-	gpio->chip.label		= dev_name(&pdev->dev);
-	gpio->chip.owner		= THIS_MODULE;
-	gpio->chip.get			= axp20x_gpio_get;
-	gpio->chip.get_direction	= axp20x_gpio_get_direction;
-	gpio->chip.set			= axp20x_gpio_set;
-	gpio->chip.direction_input	= axp20x_gpio_input;
-	gpio->chip.direction_output	= axp20x_gpio_output;
-	gpio->chip.ngpio		= 3;
-
-	gpio->desc = &axp20x_data;
-	gpio->regmap = axp20x->regmap;
-	gpio->dev = &pdev->dev;
-
-	platform_set_drvdata(pdev, gpio);
+	pctl->chip.base			= -1;
+	pctl->chip.can_sleep		= true;
+	pctl->chip.request		= gpiochip_generic_request;
+	pctl->chip.free			= gpiochip_generic_free;
+	pctl->chip.parent		= &pdev->dev;
+	pctl->chip.label		= dev_name(&pdev->dev);
+	pctl->chip.owner		= THIS_MODULE;
+	pctl->chip.get			= axp20x_gpio_get;
+	pctl->chip.get_direction	= axp20x_gpio_get_direction;
+	pctl->chip.set			= axp20x_gpio_set;
+	pctl->chip.direction_input	= axp20x_gpio_input;
+	pctl->chip.direction_output	= axp20x_gpio_output;
+	pctl->chip.ngpio		= 3;
+
+	pctl->desc = &axp20x_data;
+	pctl->regmap = axp20x->regmap;
+	pctl->dev = &pdev->dev;
+
+	platform_set_drvdata(pdev, pctl);
 
 	axp20x_build_funcs_groups(pdev);
 
@@ -401,27 +401,27 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 
 	pctrl_desc->name = dev_name(&pdev->dev);
 	pctrl_desc->owner = THIS_MODULE;
-	pctrl_desc->pins = gpio->desc->pins;
-	pctrl_desc->npins = gpio->desc->npins;
+	pctrl_desc->pins = pctl->desc->pins;
+	pctrl_desc->npins = pctl->desc->npins;
 	pctrl_desc->pctlops = &axp20x_pctrl_ops;
 	pctrl_desc->pmxops = &axp20x_pmx_ops;
 
-	gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio);
-	if (IS_ERR(gpio->pctl_dev)) {
+	pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl);
+	if (IS_ERR(pctl->pctl_dev)) {
 		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
-		return PTR_ERR(gpio->pctl_dev);
+		return PTR_ERR(pctl->pctl_dev);
 	}
 
-	ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+	ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register GPIO chip\n");
 		return ret;
 	}
 
-	ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev),
-				     gpio->desc->pins->number,
-				     gpio->desc->pins->number,
-				     gpio->desc->npins);
+	ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev),
+				     pctl->desc->pins->number,
+				     pctl->desc->pins->number,
+				     pctl->desc->npins);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to add pin range\n");
 		return ret;
@@ -432,21 +432,21 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static const struct of_device_id axp20x_gpio_match[] = {
+static const struct of_device_id axp20x_pctl_match[] = {
 	{ .compatible = "x-powers,axp209-gpio" },
 	{ }
 };
-MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
+MODULE_DEVICE_TABLE(of, axp20x_pctl_match);
 
-static struct platform_driver axp20x_gpio_driver = {
-	.probe		= axp20x_gpio_probe,
+static struct platform_driver axp20x_pctl_driver = {
+	.probe		= axp20x_pctl_probe,
 	.driver = {
 		.name		= "axp20x-gpio",
-		.of_match_table	= axp20x_gpio_match,
+		.of_match_table	= axp20x_pctl_match,
 	},
 };
 
-module_platform_driver(axp20x_gpio_driver);
+module_platform_driver(axp20x_pctl_driver);
 
 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 03/10] dt-bindings: gpio: gpio-axp209: add pinctrl features
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO,
an ADC or a LDO regulator. GPIO2 can only act as a GPIO.

This adds the pinctrl features to the driver so GPIO0/1 can be used as
ADC or LDO regulator.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/gpio/gpio-axp209.txt | 28 ++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
index a661130..4705020 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
@@ -1,4 +1,4 @@
-AXP209 GPIO controller
+AXP209 GPIO & pinctrl controller
 
 This driver follows the usual GPIO bindings found in
 Documentation/devicetree/bindings/gpio/gpio.txt
@@ -28,3 +28,29 @@ axp209: pmic at 34 {
 		#gpio-cells = <2>;
 	};
 };
+
+The GPIOs can be muxed to other functions and therefore, must be a subnode of
+axp_gpio.
+
+Example:
+
+&axp_gpio {
+	gpio0_adc: gpio0-adc {
+		pins = "GPIO0";
+		function = "adc";
+	};
+};
+
+&example_node {
+	pinctrl-names = "default";
+	pinctrl-0 = <&gpio0_adc>;
+};
+
+GPIOs and their functions
+-------------------------
+
+GPIO	|	Functions
+------------------------
+GPIO0	|	gpio_in, gpio_out, ldo, adc
+GPIO1	|	gpio_in, gpio_out, ldo, adc
+GPIO2	|	gpio_in, gpio_out
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 02/10] pinctrl: axp209: add pinctrl features
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO,
an ADC or a LDO regulator. GPIO2 can only act as a GPIO.

This adds the pinctrl features to the driver so GPIO0/1 can be used as
ADC or LDO regulator.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
---
 drivers/pinctrl/pinctrl-axp209.c | 306 +++++++++++++++++++++++++++++---
 1 file changed, 286 insertions(+), 20 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
index 4a346b7..2dc286f 100644
--- a/drivers/pinctrl/pinctrl-axp209.c
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -1,7 +1,8 @@
 /*
- * AXP20x GPIO driver
+ * AXP20x pinctrl and GPIO driver
  *
  * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Copyright (C) 2017 Quentin Schulz <quentin.schulz@free-electrons.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under  the terms of the GNU General  Public License as published by the
@@ -18,6 +19,9 @@
 #include <linux/mfd/axp20x.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
@@ -27,9 +31,52 @@
 #define AXP20X_GPIO_FUNCTION_OUT_HIGH	1
 #define AXP20X_GPIO_FUNCTION_INPUT	2
 
+#define AXP20X_FUNC_GPIO_OUT		0
+#define AXP20X_FUNC_GPIO_IN		1
+#define AXP20X_FUNC_LDO			2
+#define AXP20X_FUNC_ADC			3
+#define AXP20X_FUNCS_NB			4
+
+#define AXP20X_MUX_GPIO_OUT		0
+#define AXP20X_MUX_GPIO_IN		BIT(1)
+#define AXP20X_MUX_ADC			BIT(2)
+
+struct axp20x_pctrl_desc {
+	const struct pinctrl_pin_desc	*pins;
+	unsigned int			npins;
+	/* Stores the pins supporting LDO function. Bit offset is pin number. */
+	u8				ldo_mask;
+	/* Stores the pins supporting ADC function. Bit offset is pin number. */
+	u8				adc_mask;
+};
+
+struct axp20x_pinctrl_function {
+	const char	*name;
+	unsigned int	muxval;
+	const char	**groups;
+	unsigned int	ngroups;
+};
+
 struct axp20x_gpio {
 	struct gpio_chip	chip;
 	struct regmap		*regmap;
+	struct pinctrl_dev			*pctl_dev;
+	struct device				*dev;
+	const struct axp20x_pctrl_desc		*desc;
+	struct axp20x_pinctrl_function		funcs[AXP20X_FUNCS_NB];
+};
+
+static const struct pinctrl_pin_desc axp209_pins[] = {
+	PINCTRL_PIN(0, "GPIO0"),
+	PINCTRL_PIN(1, "GPIO1"),
+	PINCTRL_PIN(2, "GPIO2"),
+};
+
+static const struct axp20x_pctrl_desc axp20x_data = {
+	.pins	= axp209_pins,
+	.npins	= ARRAY_SIZE(axp209_pins),
+	.ldo_mask = BIT(0) | BIT(1),
+	.adc_mask = BIT(0) | BIT(1),
 };
 
 static int axp20x_gpio_get_reg(unsigned offset)
@@ -48,16 +95,7 @@ static int axp20x_gpio_get_reg(unsigned offset)
 
 static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
 {
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
-	int reg;
-
-	reg = axp20x_gpio_get_reg(offset);
-	if (reg < 0)
-		return reg;
-
-	return regmap_update_bits(gpio->regmap, reg,
-				  AXP20X_GPIO_FUNCTIONS,
-				  AXP20X_GPIO_FUNCTION_INPUT);
+	return pinctrl_gpio_direction_input(chip->base + offset);
 }
 
 static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -105,29 +143,222 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
 			      int value)
 {
+	chip->set(chip, offset, value);
+
+	return 0;
+}
+
+static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
+			    int value)
+{
 	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
 	int reg;
 
 	reg = axp20x_gpio_get_reg(offset);
 	if (reg < 0)
+		return;
+
+	regmap_update_bits(gpio->regmap, reg,
+			   AXP20X_GPIO_FUNCTIONS,
+			   value ? AXP20X_GPIO_FUNCTION_OUT_HIGH :
+			   AXP20X_GPIO_FUNCTION_OUT_LOW);
+}
+
+static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset,
+			  u8 config)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	int reg;
+
+	reg = axp20x_gpio_get_reg(offset);
+	if (reg < 0)
 		return reg;
 
-	return regmap_update_bits(gpio->regmap, reg,
-				  AXP20X_GPIO_FUNCTIONS,
-				  value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
-				  : AXP20X_GPIO_FUNCTION_OUT_LOW);
+	return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS,
+				  config);
 }
 
-static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
-			    int value)
+static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	return ARRAY_SIZE(gpio->funcs);
+}
+
+static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev,
+					unsigned int selector)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	return gpio->funcs[selector].name;
+}
+
+static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev,
+				  unsigned int selector,
+				  const char * const **groups,
+				  unsigned int *num_groups)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = gpio->funcs[selector].groups;
+	*num_groups = gpio->funcs[selector].ngroups;
+
+	return 0;
+}
+
+static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev,
+			      unsigned int function, unsigned int group)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int mask;
+
+	/* Every pin supports GPIO_OUT and GPIO_IN functions */
+	if (function <= AXP20X_FUNC_GPIO_IN)
+		return axp20x_pmx_set(pctldev, group,
+				      gpio->funcs[function].muxval);
+
+	if (function == AXP20X_FUNC_LDO)
+		mask = gpio->desc->ldo_mask;
+	else
+		mask = gpio->desc->adc_mask;
+
+	if (!(BIT(group) & mask))
+		return -EINVAL;
+
+	/*
+	 * We let the regulator framework handle the LDO muxing as muxing bits
+	 * are basically also regulators on/off bits. It's better not to enforce
+	 * any state of the regulator when selecting LDO mux so that we don't
+	 * interfere with the regulator driver.
+	 */
+	if (function == AXP20X_FUNC_LDO)
+		return 0;
+
+	return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval);
+}
+
+static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+					 struct pinctrl_gpio_range *range,
+					 unsigned int offset, bool input)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	if (input)
+		return axp20x_pmx_set(pctldev, offset,
+				      gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval);
+
+	return axp20x_pmx_set(pctldev, offset,
+			      gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval);
+}
+
+static const struct pinmux_ops axp20x_pmx_ops = {
+	.get_functions_count	= axp20x_pmx_func_cnt,
+	.get_function_name	= axp20x_pmx_func_name,
+	.get_function_groups	= axp20x_pmx_func_groups,
+	.set_mux		= axp20x_pmx_set_mux,
+	.gpio_set_direction	= axp20x_pmx_gpio_set_direction,
+	.strict			= true,
+};
+
+static int axp20x_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	return gpio->desc->npins;
+}
+
+static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
+			     const unsigned int **pins, unsigned int *num_pins)
+{
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = (unsigned int *)&gpio->desc->pins[selector];
+	*num_pins = 1;
+
+	return 0;
+}
+
+static const char *axp20x_group_name(struct pinctrl_dev *pctldev,
+				     unsigned int selector)
 {
-	axp20x_gpio_output(chip, offset, value);
+	struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev);
+
+	return gpio->desc->pins[selector].name;
+}
+
+static const struct pinctrl_ops axp20x_pctrl_ops = {
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
+	.dt_free_map		= pinconf_generic_dt_free_map,
+	.get_groups_count	= axp20x_groups_cnt,
+	.get_group_name		= axp20x_group_name,
+	.get_group_pins		= axp20x_group_pins,
+};
+
+static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask,
+					  unsigned int mask_len,
+					  struct axp20x_pinctrl_function *func,
+					  const struct pinctrl_pin_desc *pins)
+{
+	unsigned long int mask_cpy = mask;
+	const char **group;
+	unsigned int ngroups = hweight8(mask);
+	int bit;
+
+	func->ngroups = ngroups;
+	if (func->ngroups > 0) {
+		func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *),
+					    GFP_KERNEL);
+		group = func->groups;
+		for_each_set_bit(bit, &mask_cpy, mask_len) {
+			*group = pins[bit].name;
+			group++;
+		}
+	}
+}
+
+static void axp20x_build_funcs_groups(struct platform_device *pdev)
+{
+	struct axp20x_gpio *gpio = platform_get_drvdata(pdev);
+	int i, pin;
+
+	gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out";
+	gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT;
+	gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in";
+	gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN;
+	gpio->funcs[AXP20X_FUNC_LDO].name = "ldo";
+	/*
+	 * Muxval for LDO is useless as we won't use it.
+	 * See comment in axp20x_pmx_set_mux.
+	 */
+	gpio->funcs[AXP20X_FUNC_ADC].name = "adc";
+	gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC;
+
+	/* Every pin supports GPIO_OUT and GPIO_IN functions */
+	for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) {
+		gpio->funcs[i].ngroups = gpio->desc->npins;
+		gpio->funcs[i].groups = devm_kzalloc(&pdev->dev,
+						     gpio->desc->npins * sizeof(const char *),
+						     GFP_KERNEL);
+		for (pin = 0; pin < gpio->desc->npins; pin++)
+			gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name;
+	}
+
+	axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask,
+				      gpio->desc->npins,
+				      &gpio->funcs[AXP20X_FUNC_LDO],
+				      gpio->desc->pins);
+
+	axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask,
+				      gpio->desc->npins,
+				      &gpio->funcs[AXP20X_FUNC_ADC],
+				      gpio->desc->pins);
 }
 
 static int axp20x_gpio_probe(struct platform_device *pdev)
 {
 	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
 	struct axp20x_gpio *gpio;
+	struct pinctrl_desc *pctrl_desc;
 	int ret;
 
 	if (!of_device_is_available(pdev->dev.of_node))
@@ -144,6 +375,8 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 
 	gpio->chip.base			= -1;
 	gpio->chip.can_sleep		= true;
+	gpio->chip.request		= gpiochip_generic_request;
+	gpio->chip.free			= gpiochip_generic_free;
 	gpio->chip.parent		= &pdev->dev;
 	gpio->chip.label		= dev_name(&pdev->dev);
 	gpio->chip.owner		= THIS_MODULE;
@@ -154,7 +387,30 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 	gpio->chip.direction_output	= axp20x_gpio_output;
 	gpio->chip.ngpio		= 3;
 
+	gpio->desc = &axp20x_data;
 	gpio->regmap = axp20x->regmap;
+	gpio->dev = &pdev->dev;
+
+	platform_set_drvdata(pdev, gpio);
+
+	axp20x_build_funcs_groups(pdev);
+
+	pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL);
+	if (!pctrl_desc)
+		return -ENOMEM;
+
+	pctrl_desc->name = dev_name(&pdev->dev);
+	pctrl_desc->owner = THIS_MODULE;
+	pctrl_desc->pins = gpio->desc->pins;
+	pctrl_desc->npins = gpio->desc->npins;
+	pctrl_desc->pctlops = &axp20x_pctrl_ops;
+	pctrl_desc->pmxops = &axp20x_pmx_ops;
+
+	gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio);
+	if (IS_ERR(gpio->pctl_dev)) {
+		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+		return PTR_ERR(gpio->pctl_dev);
+	}
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
 	if (ret) {
@@ -162,7 +418,16 @@ static int axp20x_gpio_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
+	ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev),
+				     gpio->desc->pins->number,
+				     gpio->desc->pins->number,
+				     gpio->desc->npins);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add pin range\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n");
 
 	return 0;
 }
@@ -184,5 +449,6 @@ static struct platform_driver axp20x_gpio_driver = {
 module_platform_driver(axp20x_gpio_driver);
 
 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
-MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
+MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
+MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver");
 MODULE_LICENSE("GPL");
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 01/10] pinctrl: move gpio-axp209 to pinctrl
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cover.3ff63fdf302c6bda02ea7d160ad2aa5afee0899d.1512135804.git-series.quentin.schulz@free-electrons.com>

To prepare the driver for the upcoming pinctrl features, move the GPIO
driver AXP209 from GPIO to pinctrl subsystem.

Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
---
 drivers/gpio/Kconfig             |   6 +-
 drivers/gpio/Makefile            |   1 +-
 drivers/gpio/gpio-axp209.c       | 188 +--------------------------------
 drivers/pinctrl/Kconfig          |   6 +-
 drivers/pinctrl/Makefile         |   1 +-
 drivers/pinctrl/pinctrl-axp209.c | 188 ++++++++++++++++++++++++++++++++-
 6 files changed, 195 insertions(+), 195 deletions(-)
 delete mode 100644 drivers/gpio/gpio-axp209.c
 create mode 100644 drivers/pinctrl/pinctrl-axp209.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d6a8e85..395669b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -122,12 +122,6 @@ config GPIO_ATH79
 	  Select this option to enable GPIO driver for
 	  Atheros AR71XX/AR724X/AR913X SoC devices.
 
-config GPIO_AXP209
-	tristate "X-Powers AXP209 PMIC GPIO Support"
-	depends on MFD_AXP20X
-	help
-	  Say yes to enable GPIO support for the AXP209 PMIC
-
 config GPIO_BCM_KONA
 	bool "Broadcom Kona GPIO"
 	depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4bc24fe..bc5dd67 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT)	+= gpio-amdpt.o
 obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
 obj-$(CONFIG_GPIO_ATH79)	+= gpio-ath79.o
 obj-$(CONFIG_GPIO_ASPEED)	+= gpio-aspeed.o
-obj-$(CONFIG_GPIO_AXP209)	+= gpio-axp209.o
 obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BD9571MWV)	+= gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BRCMSTB)	+= gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c
deleted file mode 100644
index 4a346b7..0000000
--- a/drivers/gpio/gpio-axp209.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * AXP20x GPIO driver
- *
- * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under  the terms of the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <linux/device.h>
-#include <linux/gpio/driver.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/axp20x.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-#include <linux/slab.h>
-
-#define AXP20X_GPIO_FUNCTIONS		0x7
-#define AXP20X_GPIO_FUNCTION_OUT_LOW	0
-#define AXP20X_GPIO_FUNCTION_OUT_HIGH	1
-#define AXP20X_GPIO_FUNCTION_INPUT	2
-
-struct axp20x_gpio {
-	struct gpio_chip	chip;
-	struct regmap		*regmap;
-};
-
-static int axp20x_gpio_get_reg(unsigned offset)
-{
-	switch (offset) {
-	case 0:
-		return AXP20X_GPIO0_CTRL;
-	case 1:
-		return AXP20X_GPIO1_CTRL;
-	case 2:
-		return AXP20X_GPIO2_CTRL;
-	}
-
-	return -EINVAL;
-}
-
-static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
-{
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
-	int reg;
-
-	reg = axp20x_gpio_get_reg(offset);
-	if (reg < 0)
-		return reg;
-
-	return regmap_update_bits(gpio->regmap, reg,
-				  AXP20X_GPIO_FUNCTIONS,
-				  AXP20X_GPIO_FUNCTION_INPUT);
-}
-
-static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
-	unsigned int val;
-	int ret;
-
-	ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
-	if (ret)
-		return ret;
-
-	return !!(val & BIT(offset + 4));
-}
-
-static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
-{
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
-	unsigned int val;
-	int reg, ret;
-
-	reg = axp20x_gpio_get_reg(offset);
-	if (reg < 0)
-		return reg;
-
-	ret = regmap_read(gpio->regmap, reg, &val);
-	if (ret)
-		return ret;
-
-	/*
-	 * This shouldn't really happen if the pin is in use already,
-	 * or if it's not in use yet, it doesn't matter since we're
-	 * going to change the value soon anyway. Default to output.
-	 */
-	if ((val & AXP20X_GPIO_FUNCTIONS) > 2)
-		return 0;
-
-	/*
-	 * The GPIO directions are the three lowest values.
-	 * 2 is input, 0 and 1 are output
-	 */
-	return val & 2;
-}
-
-static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
-			      int value)
-{
-	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
-	int reg;
-
-	reg = axp20x_gpio_get_reg(offset);
-	if (reg < 0)
-		return reg;
-
-	return regmap_update_bits(gpio->regmap, reg,
-				  AXP20X_GPIO_FUNCTIONS,
-				  value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
-				  : AXP20X_GPIO_FUNCTION_OUT_LOW);
-}
-
-static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
-			    int value)
-{
-	axp20x_gpio_output(chip, offset, value);
-}
-
-static int axp20x_gpio_probe(struct platform_device *pdev)
-{
-	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
-	struct axp20x_gpio *gpio;
-	int ret;
-
-	if (!of_device_is_available(pdev->dev.of_node))
-		return -ENODEV;
-
-	if (!axp20x) {
-		dev_err(&pdev->dev, "Parent drvdata not set\n");
-		return -EINVAL;
-	}
-
-	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
-	if (!gpio)
-		return -ENOMEM;
-
-	gpio->chip.base			= -1;
-	gpio->chip.can_sleep		= true;
-	gpio->chip.parent		= &pdev->dev;
-	gpio->chip.label		= dev_name(&pdev->dev);
-	gpio->chip.owner		= THIS_MODULE;
-	gpio->chip.get			= axp20x_gpio_get;
-	gpio->chip.get_direction	= axp20x_gpio_get_direction;
-	gpio->chip.set			= axp20x_gpio_set;
-	gpio->chip.direction_input	= axp20x_gpio_input;
-	gpio->chip.direction_output	= axp20x_gpio_output;
-	gpio->chip.ngpio		= 3;
-
-	gpio->regmap = axp20x->regmap;
-
-	ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to register GPIO chip\n");
-		return ret;
-	}
-
-	dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id axp20x_gpio_match[] = {
-	{ .compatible = "x-powers,axp209-gpio" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
-
-static struct platform_driver axp20x_gpio_driver = {
-	.probe		= axp20x_gpio_probe,
-	.driver = {
-		.name		= "axp20x-gpio",
-		.of_match_table	= axp20x_gpio_match,
-	},
-};
-
-module_platform_driver(axp20x_gpio_driver);
-
-MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
-MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 4571cc0..58e8cc8 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -63,6 +63,12 @@ config PINCTRL_AS3722
 	  open drain configuration for the GPIO pins of AS3722 devices. It also
 	  supports the GPIO functionality through gpiolib.
 
+config PINCTRL_AXP209
+	tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support"
+	depends on MFD_AXP20X
+	help
+	  Say yes to enable pinctrl and GPIO support for the AXP209 PMIC
+
 config PINCTRL_BF54x
 	def_bool y if BF54x
 	select PINCTRL_ADI2
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index d0d4844..4777f15 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
 obj-$(CONFIG_PINCTRL_ADI2)	+= pinctrl-adi2.o
 obj-$(CONFIG_PINCTRL_ARTPEC6)	+= pinctrl-artpec6.o
 obj-$(CONFIG_PINCTRL_AS3722)	+= pinctrl-as3722.o
+obj-$(CONFIG_PINCTRL_AXP209)	+= pinctrl-axp209.o
 obj-$(CONFIG_PINCTRL_BF54x)	+= pinctrl-adi2-bf54x.o
 obj-$(CONFIG_PINCTRL_BF60x)	+= pinctrl-adi2-bf60x.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
new file mode 100644
index 0000000..4a346b7
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-axp209.c
@@ -0,0 +1,188 @@
+/*
+ * AXP20x GPIO driver
+ *
+ * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AXP20X_GPIO_FUNCTIONS		0x7
+#define AXP20X_GPIO_FUNCTION_OUT_LOW	0
+#define AXP20X_GPIO_FUNCTION_OUT_HIGH	1
+#define AXP20X_GPIO_FUNCTION_INPUT	2
+
+struct axp20x_gpio {
+	struct gpio_chip	chip;
+	struct regmap		*regmap;
+};
+
+static int axp20x_gpio_get_reg(unsigned offset)
+{
+	switch (offset) {
+	case 0:
+		return AXP20X_GPIO0_CTRL;
+	case 1:
+		return AXP20X_GPIO1_CTRL;
+	case 2:
+		return AXP20X_GPIO2_CTRL;
+	}
+
+	return -EINVAL;
+}
+
+static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	int reg;
+
+	reg = axp20x_gpio_get_reg(offset);
+	if (reg < 0)
+		return reg;
+
+	return regmap_update_bits(gpio->regmap, reg,
+				  AXP20X_GPIO_FUNCTIONS,
+				  AXP20X_GPIO_FUNCTION_INPUT);
+}
+
+static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
+	if (ret)
+		return ret;
+
+	return !!(val & BIT(offset + 4));
+}
+
+static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	unsigned int val;
+	int reg, ret;
+
+	reg = axp20x_gpio_get_reg(offset);
+	if (reg < 0)
+		return reg;
+
+	ret = regmap_read(gpio->regmap, reg, &val);
+	if (ret)
+		return ret;
+
+	/*
+	 * This shouldn't really happen if the pin is in use already,
+	 * or if it's not in use yet, it doesn't matter since we're
+	 * going to change the value soon anyway. Default to output.
+	 */
+	if ((val & AXP20X_GPIO_FUNCTIONS) > 2)
+		return 0;
+
+	/*
+	 * The GPIO directions are the three lowest values.
+	 * 2 is input, 0 and 1 are output
+	 */
+	return val & 2;
+}
+
+static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
+			      int value)
+{
+	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+	int reg;
+
+	reg = axp20x_gpio_get_reg(offset);
+	if (reg < 0)
+		return reg;
+
+	return regmap_update_bits(gpio->regmap, reg,
+				  AXP20X_GPIO_FUNCTIONS,
+				  value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
+				  : AXP20X_GPIO_FUNCTION_OUT_LOW);
+}
+
+static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
+			    int value)
+{
+	axp20x_gpio_output(chip, offset, value);
+}
+
+static int axp20x_gpio_probe(struct platform_device *pdev)
+{
+	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+	struct axp20x_gpio *gpio;
+	int ret;
+
+	if (!of_device_is_available(pdev->dev.of_node))
+		return -ENODEV;
+
+	if (!axp20x) {
+		dev_err(&pdev->dev, "Parent drvdata not set\n");
+		return -EINVAL;
+	}
+
+	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	gpio->chip.base			= -1;
+	gpio->chip.can_sleep		= true;
+	gpio->chip.parent		= &pdev->dev;
+	gpio->chip.label		= dev_name(&pdev->dev);
+	gpio->chip.owner		= THIS_MODULE;
+	gpio->chip.get			= axp20x_gpio_get;
+	gpio->chip.get_direction	= axp20x_gpio_get_direction;
+	gpio->chip.set			= axp20x_gpio_set;
+	gpio->chip.direction_input	= axp20x_gpio_input;
+	gpio->chip.direction_output	= axp20x_gpio_output;
+	gpio->chip.ngpio		= 3;
+
+	gpio->regmap = axp20x->regmap;
+
+	ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register GPIO chip\n");
+		return ret;
+	}
+
+	dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
+
+	return 0;
+}
+
+static const struct of_device_id axp20x_gpio_match[] = {
+	{ .compatible = "x-powers,axp209-gpio" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
+
+static struct platform_driver axp20x_gpio_driver = {
+	.probe		= axp20x_gpio_probe,
+	.driver = {
+		.name		= "axp20x-gpio",
+		.of_match_table	= axp20x_gpio_match,
+	},
+};
+
+module_platform_driver(axp20x_gpio_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
+MODULE_LICENSE("GPL");
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 00/10] add pinmuxing support for pins in AXP209 and AXP813 PMICs
From: Quentin Schulz @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

The AXP209 and AXP813 PMICs have several pins (respectively 3 and 2) that can
be used either as GPIOs or for other purposes (ADC or LDO here).

We already have a GPIO driver for the GPIO use of those pins on the AXP209.
Let's "upgrade" this driver to support all the functions these pins can have.

Then we add support to this driver for the AXP813 which is slighlty different
(basically a different offset in two registers and one less pin).

I suggest patches 1 to 8 go through Linus's tree and 9 and 10 via Maxime or
Chen-Yu's tree.

v4:
  - separate dt-binding patch when adding pinctrl feature,
  - use - instead of _ in DT node name,
  - remove muxing operation from pinctrl driver when choosing LDO mux in order
  to not interfere with the regulator framework,
  - add adc_mux to specify specific mux value for ADC (different between AXP209
  and AXP813),
  - misc modifications (header include reordering, unsigned int -> u8,
  new line removal),

v3:
  - add defines for GPIO funcs,
  - use again get_regs function instead of drv_data (which was implemented in
  v2),
  - use of_device_id data for device specific data (gpio_status_offset and pins
  description),
  - change compatible from axp813-pctl to axp813-gpio,
  - use axp81x DT label instead of axp813 since AXP813 and AXP818 are similar,
  - add dtsi include for all boards embedding axp813/axp818,

v2:
  - add support for AXP813 pins,
  - split into more patches so it is easier to follow the modifications,
  - reorder of some patches,
  - register all pins within the same range instead of a range per pin,

Thanks,
Quentin

Quentin Schulz (10):
  pinctrl: move gpio-axp209 to pinctrl
  pinctrl: axp209: add pinctrl features
  dt-bindings: gpio: gpio-axp209: add pinctrl features
  pinctrl: axp209: rename everything from gpio to pctl
  pinctrl: axp209: add programmable gpio_status_offset
  pinctrl: axp209: add programmable ADC muxing value
  pinctrl: axp209: add support for AXP813 GPIOs
  mfd: axp20x: add pinctrl cell for AXP813
  ARM: dtsi: axp81x: add GPIO DT node
  ARM: dtsi: axp81x: set pinmux for GPIO0/1 when used as LDOs

 Documentation/devicetree/bindings/gpio/gpio-axp209.txt |  41 +-
 arch/arm/boot/dts/axp81x.dtsi                          |  20 +-
 drivers/gpio/Kconfig                                   |   6 +-
 drivers/gpio/Makefile                                  |   1 +-
 drivers/gpio/gpio-axp209.c                             | 188 +----
 drivers/mfd/axp20x.c                                   |   3 +-
 drivers/pinctrl/Kconfig                                |   6 +-
 drivers/pinctrl/Makefile                               |   1 +-
 drivers/pinctrl/pinctrl-axp209.c                       | 477 ++++++++++-
 9 files changed, 546 insertions(+), 197 deletions(-)
 delete mode 100644 drivers/gpio/gpio-axp209.c
 create mode 100644 drivers/pinctrl/pinctrl-axp209.c

base-commit: fb20eb9d798d2f4c1a75b7fe981d72dfa8d7270d
-- 
git-series 0.9.1

^ permalink raw reply

* Applied "ASoC: ep93xx-ac97: Fix platform_get_irq's error checking" to the asoc tree
From: Mark Brown @ 2017-12-01 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4ce907b8389af30eb0677e70cf543a2b795cca12.1511970158.git.arvind.yadav.cs@gmail.com>

The patch

   ASoC: ep93xx-ac97: Fix platform_get_irq's error checking

has been applied to the asoc tree at

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 8d6fb0bce2021baf056344cb0abb2df00c5fe6d5 Mon Sep 17 00:00:00 2001
From: Arvind Yadav <arvind.yadav.cs@gmail.com>
Date: Wed, 29 Nov 2017 21:47:10 +0530
Subject: [PATCH] ASoC: ep93xx-ac97: Fix platform_get_irq's error checking

The platform_get_irq() function returns negative if an error occurs.
zero or positive number on success. platform_get_irq() error checking
for zero is not correct.

Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 sound/soc/cirrus/ep93xx-ac97.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index bbf7a9266a99..cd5a939ad608 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -365,7 +365,7 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
 {
 	struct ep93xx_ac97_info *info;
 	struct resource *res;
-	unsigned int irq;
+	int irq;
 	int ret;
 
 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
@@ -378,8 +378,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
 		return PTR_ERR(info->regs);
 
 	irq = platform_get_irq(pdev, 0);
-	if (!irq)
-		return -ENODEV;
+	if (irq <= 0)
+		return irq < 0 ? irq : -ENODEV;
 
 	ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
 			       IRQF_TRIGGER_HIGH, pdev->name, info);
-- 
2.15.0

^ 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