Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [kernel-hardening][PATCH v6 0/3] arm: Makes ptdump resuable and add WX page checking
From: Jinbum Park @ 2017-12-08 10:58 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Page table dumping code for arm64-x86 is reusable,
and they have function for WX page checking.
But arm doesn't have that.

This path series are to makes ptdump reusable,
and add WX page checking for arm.
This is heavily based on arm64 version.

v2 :
Fix a sender name of mail header, there was an mistake.
(from "jinb.park" to Jinbum Park)
Contents of patch-set are perfectly same.

v3 :
Take advantage of the existing pg_level and bits arrays
to check ro, nx prot.

v4 :
Add boolean for ro_bit, nx_bit into prot_bits
to point ro_bit, nx_bit in pg_level.
This change is suggested by Laura Abbott.

v5 :
No changes of code.
Just add Tested-by, Reviewed-by from Laura Abbott.

v6 :
USe SPDX ids in ptdump.h
Add Reviewed-by from Kees Cook.

jinb.park (3):
  arm: mm: dump: make page table dumping reusable
  arm: mm: dump: make the page table dumping seq_file optional
  arm: mm: dump: add checking for writable and executable pages

 arch/arm/Kconfig.debug        |  33 ++++++++-
 arch/arm/include/asm/ptdump.h |  43 ++++++++++++
 arch/arm/mm/Makefile          |   3 +-
 arch/arm/mm/dump.c            | 151 +++++++++++++++++++++++++++++-------------
 arch/arm/mm/init.c            |   2 +
 arch/arm/mm/ptdump_debugfs.c  |  34 ++++++++++
 6 files changed, 219 insertions(+), 47 deletions(-)
 create mode 100644 arch/arm/include/asm/ptdump.h
 create mode 100644 arch/arm/mm/ptdump_debugfs.c

-- 
1.9.1

^ permalink raw reply

* [PATCH v4 09/12] clk: qcom: Add Krait clock controller driver
From: Sricharan R @ 2017-12-08 11:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOFm3uHdFn_GxJuQ-HfQpGAM5rWOT7=DyKUGtDz6dadoxdkBcw@mail.gmail.com>

Hi Philippe,


On 12/8/2017 3:53 PM, Philippe Ombredanne wrote:
> Sricharan, Stephen,
> 
> On Fri, Dec 8, 2017 at 10:29 AM, Sricharan R <sricharan@codeaurora.org> wrote:
>> From: Stephen Boyd <sboyd@codeaurora.org>
>>
>> The Krait CPU clocks are made up of a primary mux and secondary
>> mux for each CPU and the L2, controlled via cp15 accessors. For
>> Kraits within KPSSv1 each secondary mux accepts a different aux
>> source, but on KPSSv2 each secondary mux accepts the same aux
>> source.
>>
>> Cc: <devicetree@vger.kernel.org>
>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> []
>> --- /dev/null
>> +++ b/drivers/clk/qcom/krait-cc.c
>> @@ -0,0 +1,350 @@
>> +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 and
>> + * only version 2 as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
> 
> Have you considered using the new SPDX ids? Something like this:
> 
> // SPDX-License-Identifier: GPL-2.0
> // Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> 
> Beside  being simpler and increasing the code to comment ratio by
> deleting 9 lines of boilerplate, this will also save a few trees over
> the long term each time that I print the source code of the kernel ;)
> (do not worry, I am NOT as insane as to really print the kernel
> sources, but someone more insane than me may well do it)
> 
> You may wonder about the C++ // comment style I used here... Please
> see Linus posts on the topic as well as Thomas doc patches overall for
> instructions on using the SPDX ids.
> 
> And if you were to do this for your past, present and future
> contributions (eventually these of your group), I would be quite
> grateful.
> 
> Thank you for your kind consideration
> 

Ha ok. will change it to use this one. Infact saw this feedback on other
patches, but missed updating to it while sending.

Regards,
 Sricharan

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus

^ permalink raw reply

* [kernel-hardening][PATCH v6 1/3] arm: mm: dump: make page table dumping reusable
From: Jinbum Park @ 2017-12-08 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

This patch refactors the arm page table dumping code,
so multiple tables may be registered with the framework.

This patch refers below commits of arm64.
(4674fdb9f149 ("arm64: mm: dump: make page table dumping reusable"))
(4ddb9bf83349 ("arm64: dump: Make ptdump debugfs a separate option"))

Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Laura Abbott <labbott@redhat.com>
Reviewed-by: Laura Abbott <labbott@redhat.com>
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
v6: Use SPDX ids in ptdump.h
	Add Reviewed-by from Kees Cook
---
 arch/arm/Kconfig.debug        |  6 +++-
 arch/arm/include/asm/ptdump.h | 35 +++++++++++++++++++++++
 arch/arm/mm/Makefile          |  3 +-
 arch/arm/mm/dump.c            | 65 +++++++++++++++++++------------------------
 arch/arm/mm/ptdump_debugfs.c  | 34 ++++++++++++++++++++++
 5 files changed, 104 insertions(+), 39 deletions(-)
 create mode 100644 arch/arm/include/asm/ptdump.h
 create mode 100644 arch/arm/mm/ptdump_debugfs.c

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 17685e1..e7b94db 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -3,10 +3,14 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-config ARM_PTDUMP
+config ARM_PTDUMP_CORE
+	def_bool n
+
+config ARM_PTDUMP_DEBUGFS
 	bool "Export kernel pagetable layout to userspace via debugfs"
 	depends on DEBUG_KERNEL
 	depends on MMU
+	select ARM_PTDUMP_CORE
 	select DEBUG_FS
 	---help---
 	  Say Y here if you want to show the kernel pagetable layout in a
diff --git a/arch/arm/include/asm/ptdump.h b/arch/arm/include/asm/ptdump.h
new file mode 100644
index 0000000..45d2de3
--- /dev/null
+++ b/arch/arm/include/asm/ptdump.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2014 ARM Ltd. */
+#ifndef __ASM_PTDUMP_H
+#define __ASM_PTDUMP_H
+
+#ifdef CONFIG_ARM_PTDUMP_CORE
+
+#include <linux/mm_types.h>
+#include <linux/seq_file.h>
+
+struct addr_marker {
+	unsigned long start_address;
+	char *name;
+};
+
+struct ptdump_info {
+	struct mm_struct		*mm;
+	const struct addr_marker	*markers;
+	unsigned long			base_addr;
+};
+
+void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
+#ifdef CONFIG_ARM_PTDUMP_DEBUGFS
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
+#else
+static inline int ptdump_debugfs_register(struct ptdump_info *info,
+					const char *name)
+{
+	return 0;
+}
+#endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
+
+#endif /* CONFIG_ARM_PTDUMP_CORE */
+
+#endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 01bcc33..28be5f4 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -13,7 +13,8 @@ obj-y				+= nommu.o
 obj-$(CONFIG_ARM_MPU)		+= pmsa-v7.o
 endif
 
-obj-$(CONFIG_ARM_PTDUMP)	+= dump.o
+obj-$(CONFIG_ARM_PTDUMP_CORE)	+= dump.o
+obj-$(CONFIG_ARM_PTDUMP_DEBUGFS)	+= ptdump_debugfs.o
 obj-$(CONFIG_MODULES)		+= proc-syms.o
 obj-$(CONFIG_DEBUG_VIRTUAL)	+= physaddr.o
 
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index fc3b440..8dfe7c3 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -21,11 +21,7 @@
 #include <asm/fixmap.h>
 #include <asm/memory.h>
 #include <asm/pgtable.h>
-
-struct addr_marker {
-	unsigned long start_address;
-	const char *name;
-};
+#include <asm/ptdump.h>
 
 static struct addr_marker address_markers[] = {
 	{ MODULES_VADDR,	"Modules" },
@@ -335,50 +331,36 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
 	}
 }
 
-static void walk_pgd(struct seq_file *m)
+static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
+			unsigned long start)
 {
-	pgd_t *pgd = swapper_pg_dir;
-	struct pg_state st;
-	unsigned long addr;
+	pgd_t *pgd = pgd_offset(mm, 0UL);
 	unsigned i;
-
-	memset(&st, 0, sizeof(st));
-	st.seq = m;
-	st.marker = address_markers;
+	unsigned long addr;
 
 	for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
-		addr = i * PGDIR_SIZE;
+		addr = start + i * PGDIR_SIZE;
 		if (!pgd_none(*pgd)) {
-			walk_pud(&st, pgd, addr);
+			walk_pud(st, pgd, addr);
 		} else {
-			note_page(&st, addr, 1, pgd_val(*pgd), NULL);
+			note_page(st, addr, 1, pgd_val(*pgd), NULL);
 		}
 	}
-
-	note_page(&st, 0, 0, 0, NULL);
 }
 
-static int ptdump_show(struct seq_file *m, void *v)
+void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
 {
-	walk_pgd(m);
-	return 0;
-}
+	struct pg_state st = {
+		.seq = m,
+		.marker = info->markers,
+	};
 
-static int ptdump_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, ptdump_show, NULL);
+	walk_pgd(&st, info->mm, info->base_addr);
+	note_page(&st, 0, 0, 0, NULL);
 }
 
-static const struct file_operations ptdump_fops = {
-	.open		= ptdump_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int ptdump_init(void)
+static void ptdump_initialize(void)
 {
-	struct dentry *pe;
 	unsigned i, j;
 
 	for (i = 0; i < ARRAY_SIZE(pg_level); i++)
@@ -387,9 +369,18 @@ static int ptdump_init(void)
 				pg_level[i].mask |= pg_level[i].bits[j].mask;
 
 	address_markers[2].start_address = VMALLOC_START;
+}
 
-	pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
-				 &ptdump_fops);
-	return pe ? 0 : -ENOMEM;
+static struct ptdump_info kernel_ptdump_info = {
+	.mm = &init_mm,
+	.markers = address_markers,
+	.base_addr = 0,
+};
+
+static int ptdump_init(void)
+{
+	ptdump_initialize();
+	return ptdump_debugfs_register(&kernel_ptdump_info,
+					"kernel_page_tables");
 }
 __initcall(ptdump_init);
diff --git a/arch/arm/mm/ptdump_debugfs.c b/arch/arm/mm/ptdump_debugfs.c
new file mode 100644
index 0000000..be8d87b
--- /dev/null
+++ b/arch/arm/mm/ptdump_debugfs.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptdump.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+	struct ptdump_info *info = m->private;
+
+	ptdump_walk_pgd(m, info);
+	return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ptdump_show, inode->i_private);
+}
+
+static const struct file_operations ptdump_fops = {
+	.open		= ptdump_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
+{
+	struct dentry *pe;
+
+	pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
+	return pe ? 0 : -ENOMEM;
+
+}
-- 
1.9.1

^ permalink raw reply related

* [kernel-hardening][PATCH v6 2/3] arm: mm: dump: make the page table dumping seq_file optional
From: Jinbum Park @ 2017-12-08 11:01 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes the page table dumping seq_file optional.
It makes the page table dumping code usable for other cases.

This patch refers below commit of arm64.
(ae5d1cf358a5
("arm64: dump: Make the page table dumping seq_file optional"))

Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Laura Abbott <labbott@redhat.com>
Reviewed-by: Laura Abbott <labbott@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
v6: No changes
    (Just add Reviewed-by from Kees Cook)
---
 arch/arm/mm/dump.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 8dfe7c3..43a2bee 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -34,6 +34,18 @@
 	{ -1,			NULL },
 };
 
+#define pt_dump_seq_printf(m, fmt, args...) \
+({                      \
+	if (m)					\
+		seq_printf(m, fmt, ##args);	\
+})
+
+#define pt_dump_seq_puts(m, fmt)    \
+({						\
+	if (m)					\
+		seq_printf(m, fmt);	\
+})
+
 struct pg_state {
 	struct seq_file *seq;
 	const struct addr_marker *marker;
@@ -210,7 +222,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits, size_t
 			s = bits->clear;
 
 		if (s)
-			seq_printf(st->seq, " %s", s);
+			pt_dump_seq_printf(st->seq, " %s", s);
 	}
 }
 
@@ -224,7 +236,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
 		st->level = level;
 		st->current_prot = prot;
 		st->current_domain = domain;
-		seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+		pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
 	} else if (prot != st->current_prot || level != st->level ||
 		   domain != st->current_domain ||
 		   addr >= st->marker[1].start_address) {
@@ -232,7 +244,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
 		unsigned long delta;
 
 		if (st->current_prot) {
-			seq_printf(st->seq, "0x%08lx-0x%08lx   ",
+			pt_dump_seq_printf(st->seq, "0x%08lx-0x%08lx   ",
 				   st->start_address, addr);
 
 			delta = (addr - st->start_address) >> 10;
@@ -240,17 +252,19 @@ static void note_page(struct pg_state *st, unsigned long addr,
 				delta >>= 10;
 				unit++;
 			}
-			seq_printf(st->seq, "%9lu%c", delta, *unit);
+			pt_dump_seq_printf(st->seq, "%9lu%c", delta, *unit);
 			if (st->current_domain)
-				seq_printf(st->seq, " %s", st->current_domain);
+				pt_dump_seq_printf(st->seq, " %s",
+							st->current_domain);
 			if (pg_level[st->level].bits)
 				dump_prot(st, pg_level[st->level].bits, pg_level[st->level].num);
-			seq_printf(st->seq, "\n");
+			pt_dump_seq_printf(st->seq, "\n");
 		}
 
 		if (addr >= st->marker[1].start_address) {
 			st->marker++;
-			seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+			pt_dump_seq_printf(st->seq, "---[ %s ]---\n",
+							st->marker->name);
 		}
 		st->start_address = addr;
 		st->current_prot = prot;
-- 
1.9.1

^ permalink raw reply related

* [kernel-hardening][PATCH v6 3/3] arm: mm: dump: add checking for writable and executable pages
From: Jinbum Park @ 2017-12-08 11:02 UTC (permalink / raw)
  To: linux-arm-kernel

Page mappings with full RWX permissions are a security risk.
x86, arm64 has an option to walk the page tables
and dump any bad pages.

(1404d6f13e47
("arm64: dump: Add checking for writable and exectuable pages"))
Add a similar implementation for arm.

Reviewed-by: Kees Cook <keescook@chromium.org>
Tested-by: Laura Abbott <labbott@redhat.com>
Reviewed-by: Laura Abbott <labbott@redhat.com>
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
v6: No changes
    (Just add Reviewed-by from Kees Cook)
---
 arch/arm/Kconfig.debug        | 27 ++++++++++++++++++++
 arch/arm/include/asm/ptdump.h |  8 ++++++
 arch/arm/mm/dump.c            | 58 ++++++++++++++++++++++++++++++++++++++++++-
 arch/arm/mm/init.c            |  2 ++
 4 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index e7b94db..78a6470 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -20,6 +20,33 @@ config ARM_PTDUMP_DEBUGFS
 	  kernel.
 	  If in doubt, say "N"
 
+config DEBUG_WX
+	bool "Warn on W+X mappings at boot"
+	select ARM_PTDUMP_CORE
+	---help---
+		Generate a warning if any W+X mappings are found at boot.
+
+		This is useful for discovering cases where the kernel is leaving
+		W+X mappings after applying NX, as such mappings are a security risk.
+
+		Look for a message in dmesg output like this:
+
+			arm/mm: Checked W+X mappings: passed, no W+X pages found.
+
+		or like this, if the check failed:
+
+			arm/mm: Checked W+X mappings: FAILED, <N> W+X pages found.
+
+		Note that even if the check fails, your kernel is possibly
+		still fine, as W+X mappings are not a security hole in
+		themselves, what they do is that they make the exploitation
+		of other unfixed kernel bugs easier.
+
+		There is no runtime or memory usage effect of this option
+		once the kernel has booted up - it's a one time check.
+
+		If in doubt, say "Y".
+
 # RMK wants arm kernels compiled with frame pointers or stack unwinding.
 # If you know what you are doing and are willing to live without stack
 # traces, you can get a slightly smaller kernel by setting this option to
diff --git a/arch/arm/include/asm/ptdump.h b/arch/arm/include/asm/ptdump.h
index 45d2de3..3ebf971 100644
--- a/arch/arm/include/asm/ptdump.h
+++ b/arch/arm/include/asm/ptdump.h
@@ -30,6 +30,14 @@ static inline int ptdump_debugfs_register(struct ptdump_info *info,
 }
 #endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
 
+void ptdump_check_wx(void);
+
 #endif /* CONFIG_ARM_PTDUMP_CORE */
 
+#ifdef CONFIG_DEBUG_WX
+#define debug_checkwx() ptdump_check_wx()
+#else
+#define debug_checkwx() do { } while (0)
+#endif
+
 #endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 43a2bee..084779c 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -52,6 +52,8 @@ struct pg_state {
 	unsigned long start_address;
 	unsigned level;
 	u64 current_prot;
+	bool check_wx;
+	unsigned long wx_pages;
 	const char *current_domain;
 };
 
@@ -60,6 +62,8 @@ struct prot_bits {
 	u64		val;
 	const char	*set;
 	const char	*clear;
+	bool		ro_bit;
+	bool		nx_bit;
 };
 
 static const struct prot_bits pte_bits[] = {
@@ -73,11 +77,13 @@ struct prot_bits {
 		.val	= L_PTE_RDONLY,
 		.set	= "ro",
 		.clear	= "RW",
+		.ro_bit	= true,
 	}, {
 		.mask	= L_PTE_XN,
 		.val	= L_PTE_XN,
 		.set	= "NX",
 		.clear	= "x ",
+		.nx_bit	= true,
 	}, {
 		.mask	= L_PTE_SHARED,
 		.val	= L_PTE_SHARED,
@@ -141,11 +147,13 @@ struct prot_bits {
 		.val	= L_PMD_SECT_RDONLY | PMD_SECT_AP2,
 		.set	= "ro",
 		.clear	= "RW",
+		.ro_bit	= true,
 #elif __LINUX_ARM_ARCH__ >= 6
 	{
 		.mask	= PMD_SECT_APX | PMD_SECT_AP_READ | PMD_SECT_AP_WRITE,
 		.val	= PMD_SECT_APX | PMD_SECT_AP_WRITE,
 		.set	= "    ro",
+		.ro_bit	= true,
 	}, {
 		.mask	= PMD_SECT_APX | PMD_SECT_AP_READ | PMD_SECT_AP_WRITE,
 		.val	= PMD_SECT_AP_WRITE,
@@ -164,6 +172,7 @@ struct prot_bits {
 		.mask   = PMD_SECT_AP_READ | PMD_SECT_AP_WRITE,
 		.val    = 0,
 		.set    = "    ro",
+		.ro_bit	= true,
 	}, {
 		.mask   = PMD_SECT_AP_READ | PMD_SECT_AP_WRITE,
 		.val    = PMD_SECT_AP_WRITE,
@@ -182,6 +191,7 @@ struct prot_bits {
 		.val	= PMD_SECT_XN,
 		.set	= "NX",
 		.clear	= "x ",
+		.nx_bit	= true,
 	}, {
 		.mask	= PMD_SECT_S,
 		.val	= PMD_SECT_S,
@@ -194,6 +204,8 @@ struct pg_level {
 	const struct prot_bits *bits;
 	size_t num;
 	u64 mask;
+	const struct prot_bits *ro_bit;
+	const struct prot_bits *nx_bit;
 };
 
 static struct pg_level pg_level[] = {
@@ -226,6 +238,23 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits, size_t
 	}
 }
 
+static void note_prot_wx(struct pg_state *st, unsigned long addr)
+{
+	if (!st->check_wx)
+		return;
+	if ((st->current_prot & pg_level[st->level].ro_bit->mask) ==
+				pg_level[st->level].ro_bit->val)
+		return;
+	if ((st->current_prot & pg_level[st->level].nx_bit->mask) ==
+				pg_level[st->level].nx_bit->val)
+		return;
+
+	WARN_ONCE(1, "arm/mm: Found insecure W+X mapping at address %pS\n",
+			(void *)st->start_address);
+
+	st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
+}
+
 static void note_page(struct pg_state *st, unsigned long addr,
 		      unsigned int level, u64 val, const char *domain)
 {
@@ -244,6 +273,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
 		unsigned long delta;
 
 		if (st->current_prot) {
+			note_prot_wx(st, addr);
 			pt_dump_seq_printf(st->seq, "0x%08lx-0x%08lx   ",
 				   st->start_address, addr);
 
@@ -367,6 +397,7 @@ void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
 	struct pg_state st = {
 		.seq = m,
 		.marker = info->markers,
+		.check_wx = false,
 	};
 
 	walk_pgd(&st, info->mm, info->base_addr);
@@ -379,8 +410,13 @@ static void ptdump_initialize(void)
 
 	for (i = 0; i < ARRAY_SIZE(pg_level); i++)
 		if (pg_level[i].bits)
-			for (j = 0; j < pg_level[i].num; j++)
+			for (j = 0; j < pg_level[i].num; j++) {
 				pg_level[i].mask |= pg_level[i].bits[j].mask;
+				if (pg_level[i].bits[j].ro_bit)
+					pg_level[i].ro_bit = &pg_level[i].bits[j];
+				if (pg_level[i].bits[j].nx_bit)
+					pg_level[i].nx_bit = &pg_level[i].bits[j];
+			}
 
 	address_markers[2].start_address = VMALLOC_START;
 }
@@ -391,6 +427,26 @@ static void ptdump_initialize(void)
 	.base_addr = 0,
 };
 
+void ptdump_check_wx(void)
+{
+	struct pg_state st = {
+		.seq = NULL,
+		.marker = (struct addr_marker[]) {
+			{ 0, NULL},
+			{ -1, NULL},
+		},
+		.check_wx = true,
+	};
+
+	walk_pgd(&st, &init_mm, 0);
+	note_page(&st, 0, 0, 0, NULL);
+	if (st.wx_pages)
+		pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n",
+			st.wx_pages);
+	else
+		pr_info("Checked W+X mappings: passed, no W+X pages found\n");
+}
+
 static int ptdump_init(void)
 {
 	ptdump_initialize();
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index a1f11a7..bd6f451 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -36,6 +36,7 @@
 #include <asm/system_info.h>
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
+#include <asm/ptdump.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -738,6 +739,7 @@ static int __mark_rodata_ro(void *unused)
 void mark_rodata_ro(void)
 {
 	stop_machine(__mark_rodata_ro, NULL, NULL);
+	debug_checkwx();
 }
 
 void set_kernel_text_rw(void)
-- 
1.9.1

^ permalink raw reply related

* CC[NI] driver fixes for 4.15
From: Pawel Moll @ 2017-12-08 11:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

A small series of fixes for the CCN driver, plus (one time only, guest
staring) one for CCI.

Please consider pulling:

The following changes since commit 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323:

  Linux 4.15-rc1 (2017-11-26 16:01:47 -0800)

are available in the git repository at:

  git://git.linaro.org/people/pawel.moll/linux.git tags/ccn/fixes-for-4.15

for you to fetch changes up to b69f63ebf553504739cc8534cbed31bd530c6f0b:

  bus: arm-ccn: fix module unloading Error: Removing state 147 which has instances left. (2017-12-04 17:15:20 +0000)

----------------------------------------------------------------
bus: ARM CCN and CCI PMU driver fixes

This is a bunch of fixes CCN and (guest starring this time) CCI drivers.

* Check for potential of failed allocation for the driver name string
* Manage CPU ID properly at allocation (both CCN and CCI)
* Fix module unload warnings related to objects release order
* Small improvements like using allocating printfs and proper
  attributes constification

The one fixing potential issues have been cc-ed to stable.

----------------------------------------------------------------
Arvind Yadav (1):
      bus: arm-ccn: constify attribute_group structures.

Christophe JAILLET (2):
      bus: arm-ccn: Check memory allocation failure
      bus: arm-ccn: Simplify code

Kim Phillips (1):
      bus: arm-ccn: fix module unloading Error: Removing state 147 which has instances left.

Marc Zyngier (2):
      bus: arm-ccn: Fix use of smp_processor_id() in preemptible context
      bus: arm-cci: Fix use of smp_processor_id() in preemptible context

 drivers/bus/arm-cci.c |  7 +++++--
 drivers/bus/arm-ccn.c | 25 +++++++++++++++----------
 2 files changed, 20 insertions(+), 12 deletions(-)

^ permalink raw reply

* [PATCH net v3] net: phy: meson-gxl: detect LPA corruption
From: Jerome Brunet @ 2017-12-08 11:08 UTC (permalink / raw)
  To: linux-arm-kernel

The purpose of this change is to fix the incorrect detection of the link
partner (LP) advertised capabilities which sometimes happens with this PHY
(roughly 1 time in a dozen)

This issue may cause the link to be negotiated at 10Mbps/Full or
10Mbps/Half when 100MBps/Full is actually possible. In some case, the link
is even completely broken and no communication is possible.

To detect the corruption, we must look for a magic undocumented bit in the
WOL bank (hint given by the SoC vendor kernel) but this is not enough to
cover all cases. We also have to look at the LPA ack. If the LP supports
Aneg but did not ack our base code when aneg is completed, we assume
something went wrong.

The detection of a corrupted LPA triggers a restart of the aneg process.
This solves the problem but may take up to 6 retries to complete.

Fixes: 7334b3e47aee ("net: phy: Add Meson GXL Internal PHY driver")
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---

I suppose this patch probably seems a bit hacky, especially the part
about the link partner acknowledge. I'm trying to figure out if the
value in MII_LPA makes sense but I don't have such a deep knowledge
of the ethernet spec.

To me, it does not makes sense for the LP to support ANEG (Bit 1 in
MII_EXPENSION), the aneg to have successfully complete and, at the
same time, LP does not ACK our base code word, which we should have
sent during this aneg.

If you think this may have unintended consequences or if you have
an idea to do this differently, feel free to let me know.

This fix has been tested on the libretech-cc and khadas VIM

The v2 [0] had dependencies on other changes which were not fixes.
This v3 is re-implementation of v2 without the dependencies to be
merged as a fix and easily backportable.

All the ugly phy_write() with hexadecimal values will go away when
then clean-up gets through.

[0]: https://lkml.kernel.org/r/20171207142715.32578-6-jbrunet at baylibre.com

 drivers/net/phy/meson-gxl.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c
index 1ea69b7585d9..700007dd4be5 100644
--- a/drivers/net/phy/meson-gxl.c
+++ b/drivers/net/phy/meson-gxl.c
@@ -22,6 +22,7 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/netdevice.h>
+#include <linux/bitfield.h>
 
 static int meson_gxl_config_init(struct phy_device *phydev)
 {
@@ -50,6 +51,77 @@ static int meson_gxl_config_init(struct phy_device *phydev)
 	return 0;
 }
 
+/* This function is provided to cope with the possible failures of this phy
+ * during aneg process. When aneg fails, the PHY reports that aneg is done
+ * but the value found in MII_LPA is wrong:
+ *  - Early failures: MII_LPA is just 0x0001. if MII_EXPANSION reports that
+ *    the link partner (LP) supports aneg but the LP never acked our base
+ *    code word, it is likely that we never sent it to begin with.
+ *  - Late failures: MII_LPA is filled with a value which seems to make sense
+ *    but it actually is not what the LP is advertising. It seems that we
+ *    can detect this using a magic bit in the WOL bank (reg 12 - bit 12).
+ *    If this particular bit is not set when aneg is reported being done,
+ *    it means MII_LPA is likely to be wrong.
+ *
+ * In both case, forcing a restart of the aneg process solve the problem.
+ * When this failure happens, the first retry is usually successful but,
+ * in some cases, it may take up to 6 retries to get a decent result
+ */
+int meson_gxl_read_status(struct phy_device *phydev)
+{
+	int ret, wol, lpa, exp;
+
+	if (phydev->autoneg == AUTONEG_ENABLE) {
+		ret = genphy_aneg_done(phydev);
+		if (ret < 0)
+			return ret;
+		else if (!ret)
+			goto read_status_continue;
+
+		/* Need to access WOL bank, make sure the access is open */
+		ret = phy_write(phydev, 0x14, 0x0000);
+		if (ret)
+			return ret;
+		ret = phy_write(phydev, 0x14, 0x0400);
+		if (ret)
+			return ret;
+		ret = phy_write(phydev, 0x14, 0x0000);
+		if (ret)
+			return ret;
+		ret = phy_write(phydev, 0x14, 0x0400);
+		if (ret)
+			return ret;
+
+		/* Request LPI_STATUS WOL register */
+		ret = phy_write(phydev, 0x14, 0x8D80);
+		if (ret)
+			return ret;
+
+		/* Read LPI_STATUS value */
+		wol = phy_read(phydev, 0x15);
+		if (wol < 0)
+			return wol;
+
+		lpa = phy_read(phydev, MII_LPA);
+		if (lpa < 0)
+			return lpa;
+
+		exp = phy_read(phydev, MII_EXPANSION);
+		if (exp < 0)
+			return exp;
+
+		if (!(wol & BIT(12)) ||
+		    ((exp & EXPANSION_NWAY) && !(lpa & LPA_LPACK))) {
+			/* Looks like aneg failed after all */
+			phydev_dbg(phydev, "LPA corruption - aneg restart\n");
+			return genphy_restart_aneg(phydev);
+		}
+	}
+
+read_status_continue:
+	return genphy_read_status(phydev);
+}
+
 static struct phy_driver meson_gxl_phy[] = {
 	{
 		.phy_id		= 0x01814400,
@@ -60,7 +132,7 @@ static struct phy_driver meson_gxl_phy[] = {
 		.config_init	= meson_gxl_config_init,
 		.config_aneg	= genphy_config_aneg,
 		.aneg_done      = genphy_aneg_done,
-		.read_status	= genphy_read_status,
+		.read_status	= meson_gxl_read_status,
 		.suspend        = genphy_suspend,
 		.resume         = genphy_resume,
 	},
-- 
2.14.3

^ permalink raw reply related

* [kernel-hardening][PATCH] arm: mm: idmap: Mark variables as ro_after_init
From: Jinbum Park @ 2017-12-08 11:13 UTC (permalink / raw)
  To: linux-arm-kernel

idmap_pgd, arch_phys_to_idmap_offset are setup once
while init stage, and never changed after that.
so, it is good candidate for __ro_after_init.

Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
 arch/arm/mm/idmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 10bfba8..1d1edd0 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -16,8 +16,8 @@
  * are not supported on any CPU using the idmap tables as its current
  * page tables.
  */
-pgd_t *idmap_pgd;
-long long arch_phys_to_idmap_offset;
+pgd_t *idmap_pgd __ro_after_init;
+long long arch_phys_to_idmap_offset __ro_after_init;
 
 #ifdef CONFIG_ARM_LPAE
 static void idmap_add_pmd(pud_t *pud, unsigned long addr, unsigned long end,
-- 
1.9.1

^ permalink raw reply related

* [PATCH] PCI: xgene: Remove leftover pci_scan_child_bus() call
From: Lorenzo Pieralisi @ 2017-12-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171121154931.7724-1-lorenzo.pieralisi@arm.com>

Hi Tanmay,

On Tue, Nov 21, 2017 at 03:49:31PM +0000, Lorenzo Pieralisi wrote:
> The changes in commit 9af275be15f7 ("PCI: xgene: Convert PCI scan API to
> pci_scan_root_bus_bridge()") converted the xgene PCI host driver to
> the new pci_scan_root_bus_bridge() bus scanning API but erroneously left
> the existing pci_scan_child_bus() call in place which resulted in duplicate
> PCI bus enumerations.
> 
> Remove the leftover pci_scan_child_bus() call to properly complete the API
> conversion.
> 
> Fixes: 9af275be15f7 ("PCI: xgene: Convert PCI scan API to pci_scan_root_bus_bridge()")
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: Tanmay Inamdar <tinamdar@apm.com>
> ---
>  drivers/pci/host/pci-xgene.c | 1 -
>  1 file changed, 1 deletion(-)

Would you mind testing this fix and tag accordingly so that I can ask
Bjorn to pull it please ?

Thanks,
Lorenzo

> diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
> index 465aa2a..e60c457 100644
> --- a/drivers/pci/host/pci-xgene.c
> +++ b/drivers/pci/host/pci-xgene.c
> @@ -668,7 +668,6 @@ static int xgene_pcie_probe(struct platform_device *pdev)
>  
>  	bus = bridge->bus;
>  
> -	pci_scan_child_bus(bus);
>  	pci_assign_unassigned_bus_resources(bus);
>  	list_for_each_entry(child, &bus->children, node)
>  		pcie_bus_configure_settings(child);
> -- 
> 2.9.5
> 

^ permalink raw reply

* [PATCH v9 0/6] stm32 clocksource driver rework
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

version 9:
 - rebased on timer/master where timer_of_cleanup() exist
 - fix the comments done by Daniel on v8
 - reword commits message to be more explicit about 16 bits counter issue
 - add one patch about copyrights and licences
   
version 8:
 - rebased on timers/core
 - change timer_of_exit() name to timer_of_cleanup()
 - update stm32 clocksource driver to use this function

version 7:
 - reword "clocksource: stm32: only use 32 bits timers" commit message
   to give more details about why 16 bits are problematics.

version 6:
 - add dedicated patch min delta change
 - rework commit messages, I hope it will be better now
 - change new function name from timer_of_deinit to timer_of_exit
 - make stm32_clock_event_set_next_event() safer like done in other
   drivers

version 6:
- add timer_of_deinit function in core
- rework failure cases in probe function

version 5:
- rebase on top of timer/core branch
- rework commit message of the first patch

version 4:
- split patch in 3 parts
  - convert code to timer_of
  - only use 32 bits timers
  - add clocksource support

version 3:
- fix comments done by Daniel
- use timer_of helper functions

version 2:
- fix uninitialized variable

Benjamin Gaignard (6):
  clocksource: stm32: convert driver to timer_of
  clocksource: stm32: increase min delta value
  clocksource: stm32: only use 32 bits timers
  clocksource: stm32: add clocksource support
  clocksource: stm32: Update license and copyright
  arm: dts: stm32: remove useless clocksource nodes

 arch/arm/boot/dts/stm32f429.dtsi  |  32 -----
 arch/arm/boot/dts/stm32f746.dtsi  |  32 -----
 drivers/clocksource/Kconfig       |   1 +
 drivers/clocksource/timer-stm32.c | 253 +++++++++++++++++++++-----------------
 4 files changed, 139 insertions(+), 179 deletions(-)

-- 
2.15.0

^ permalink raw reply

* [PATCH v9 1/6] clocksource: stm32: convert driver to timer_of
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

Convert driver to use timer_of helpers. This allow to remove
custom proprietary structure.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 drivers/clocksource/Kconfig       |   1 +
 drivers/clocksource/timer-stm32.c | 160 ++++++++++++++------------------------
 2 files changed, 58 insertions(+), 103 deletions(-)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index c729a88007d0..28bc55951512 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -269,6 +269,7 @@ config CLKSRC_STM32
 	bool "Clocksource for STM32 SoCs" if !ARCH_STM32
 	depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
 	select CLKSRC_MMIO
+	select TIMER_OF
 
 config CLKSRC_MPS2
 	bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 8f2423789ba9..fc61fd18a182 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -17,6 +17,8 @@
 #include <linux/clk.h>
 #include <linux/reset.h>
 
+#include "timer-of.h"
+
 #define TIM_CR1		0x00
 #define TIM_DIER	0x0c
 #define TIM_SR		0x10
@@ -34,117 +36,84 @@
 
 #define TIM_EGR_UG	BIT(0)
 
-struct stm32_clock_event_ddata {
-	struct clock_event_device evtdev;
-	unsigned periodic_top;
-	void __iomem *base;
-};
-
-static int stm32_clock_event_shutdown(struct clock_event_device *evtdev)
+static int stm32_clock_event_shutdown(struct clock_event_device *evt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
-	void *base = data->base;
+	struct timer_of *to = to_timer_of(evt);
 
-	writel_relaxed(0, base + TIM_CR1);
+	writel_relaxed(0, timer_of_base(to) + TIM_CR1);
 	return 0;
 }
 
-static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev)
+static int stm32_clock_event_set_periodic(struct clock_event_device *evt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
-	void *base = data->base;
+	struct timer_of *to = to_timer_of(evt);
+
+	writel_relaxed(timer_of_period(to), timer_of_base(to) + TIM_ARR);
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
 
-	writel_relaxed(data->periodic_top, base + TIM_ARR);
-	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1);
 	return 0;
 }
 
 static int stm32_clock_event_set_next_event(unsigned long evt,
-					    struct clock_event_device *evtdev)
+					    struct clock_event_device *clkevt)
 {
-	struct stm32_clock_event_ddata *data =
-		container_of(evtdev, struct stm32_clock_event_ddata, evtdev);
+	struct timer_of *to = to_timer_of(clkevt);
 
-	writel_relaxed(evt, data->base + TIM_ARR);
+	writel_relaxed(evt, timer_of_base(to) + TIM_ARR);
 	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
-		       data->base + TIM_CR1);
+		       timer_of_base(to) + TIM_CR1);
 
 	return 0;
 }
 
 static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 {
-	struct stm32_clock_event_ddata *data = dev_id;
+	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
+	struct timer_of *to = to_timer_of(evt);
 
-	writel_relaxed(0, data->base + TIM_SR);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
-	data->evtdev.event_handler(&data->evtdev);
+	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
 }
 
-static struct stm32_clock_event_ddata clock_event_ddata = {
-	.evtdev = {
-		.name = "stm32 clockevent",
-		.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
-		.set_state_shutdown = stm32_clock_event_shutdown,
-		.set_state_periodic = stm32_clock_event_set_periodic,
-		.set_state_oneshot = stm32_clock_event_shutdown,
-		.tick_resume = stm32_clock_event_shutdown,
-		.set_next_event = stm32_clock_event_set_next_event,
-		.rating = 200,
-	},
-};
-
-static int __init stm32_clockevent_init(struct device_node *np)
+static int __init stm32_clockevent_init(struct device_node *node)
 {
-	struct stm32_clock_event_ddata *data = &clock_event_ddata;
-	struct clk *clk;
 	struct reset_control *rstc;
-	unsigned long rate, max_delta;
-	int irq, ret, bits, prescaler = 1;
-
-	clk = of_clk_get(np, 0);
-	if (IS_ERR(clk)) {
-		ret = PTR_ERR(clk);
-		pr_err("failed to get clock for clockevent (%d)\n", ret);
-		goto err_clk_get;
-	}
-
-	ret = clk_prepare_enable(clk);
-	if (ret) {
-		pr_err("failed to enable timer clock for clockevent (%d)\n",
-		       ret);
-		goto err_clk_enable;
-	}
-
-	rate = clk_get_rate(clk);
-
-	rstc = of_reset_control_get(np, NULL);
+	unsigned long max_delta;
+	int ret, bits, prescaler = 1;
+	struct timer_of *to;
+
+	to = kzalloc(sizeof(*to), GFP_KERNEL);
+	if (!to)
+		return -ENOMEM;
+
+	to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE;
+	to->clkevt.name = "stm32_clockevent";
+	to->clkevt.rating = 200;
+	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
+	to->clkevt.set_state_shutdown = stm32_clock_event_shutdown;
+	to->clkevt.set_state_periodic = stm32_clock_event_set_periodic;
+	to->clkevt.set_state_oneshot = stm32_clock_event_shutdown;
+	to->clkevt.tick_resume = stm32_clock_event_shutdown;
+	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
+
+	to->of_irq.handler = stm32_clock_event_handler;
+
+	ret = timer_of_init(node, to);
+	if (ret)
+		goto err;
+
+	rstc = of_reset_control_get(node, NULL);
 	if (!IS_ERR(rstc)) {
 		reset_control_assert(rstc);
 		reset_control_deassert(rstc);
 	}
 
-	data->base = of_iomap(np, 0);
-	if (!data->base) {
-		ret = -ENXIO;
-		pr_err("failed to map registers for clockevent\n");
-		goto err_iomap;
-	}
-
-	irq = irq_of_parse_and_map(np, 0);
-	if (!irq) {
-		ret = -EINVAL;
-		pr_err("%pOF: failed to get irq.\n", np);
-		goto err_get_irq;
-	}
-
 	/* Detect whether the timer is 16 or 32 bits */
-	writel_relaxed(~0U, data->base + TIM_ARR);
-	max_delta = readl_relaxed(data->base + TIM_ARR);
+	writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
+	max_delta = readl_relaxed(timer_of_base(to) + TIM_ARR);
 	if (max_delta == ~0U) {
 		prescaler = 1;
 		bits = 32;
@@ -152,38 +121,23 @@ static int __init stm32_clockevent_init(struct device_node *np)
 		prescaler = 1024;
 		bits = 16;
 	}
-	writel_relaxed(0, data->base + TIM_ARR);
-
-	writel_relaxed(prescaler - 1, data->base + TIM_PSC);
-	writel_relaxed(TIM_EGR_UG, data->base + TIM_EGR);
-	writel_relaxed(TIM_DIER_UIE, data->base + TIM_DIER);
-	writel_relaxed(0, data->base + TIM_SR);
+	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
 
-	data->periodic_top = DIV_ROUND_CLOSEST(rate, prescaler * HZ);
+	writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
+	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
+	writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
-	clockevents_config_and_register(&data->evtdev,
-					DIV_ROUND_CLOSEST(rate, prescaler),
-					0x1, max_delta);
-
-	ret = request_irq(irq, stm32_clock_event_handler, IRQF_TIMER,
-			"stm32 clockevent", data);
-	if (ret) {
-		pr_err("%pOF: failed to request irq.\n", np);
-		goto err_get_irq;
-	}
+	clockevents_config_and_register(&to->clkevt,
+					timer_of_period(to), 0x1, max_delta);
 
 	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
-			np, bits);
+			node, bits);
 
-	return ret;
+	return 0;
 
-err_get_irq:
-	iounmap(data->base);
-err_iomap:
-	clk_disable_unprepare(clk);
-err_clk_enable:
-	clk_put(clk);
-err_clk_get:
+err:
+	kfree(to);
 	return ret;
 }
 
-- 
2.15.0

^ permalink raw reply related

* [PATCH v9 2/6] clocksource: stm32: increase min delta value
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

The CPU is a CortexM4 @ 200MHZ and the clocks driving
the timers are at 90MHZ with a min delta at 1 you could
have an interrupt each 0.01 ms which is really to much.
By increase it to 0x60 it give more time (around 1 ms)
to CPU to handle the interrupt.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index fc61fd18a182..a45f1f1cd040 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -36,6 +36,12 @@
 
 #define TIM_EGR_UG	BIT(0)
 
+/*
+ * The clock driving the hardware is at 90MHZ with a MIN_DELTA
+ * at 0x60 it gives around 1 ms to the CPU to handle the interrupt
+ */
+#define MIN_DELTA	0x60
+
 static int stm32_clock_event_shutdown(struct clock_event_device *evt)
 {
 	struct timer_of *to = to_timer_of(evt);
@@ -129,7 +135,8 @@ static int __init stm32_clockevent_init(struct device_node *node)
 	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
 	clockevents_config_and_register(&to->clkevt,
-					timer_of_period(to), 0x1, max_delta);
+					timer_of_period(to),
+					MIN_DELTA, max_delta);
 
 	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
 			node, bits);
-- 
2.15.0

^ permalink raw reply related

* [PATCH v9 3/6] clocksource: stm32: only use 32 bits timers
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

The clock driving counters is at 90MHz so the maximum period
for 16 bis counters is around 728us (2^16 / 90.000.000).
For 32 bits counters this period is close 47 secondes which is
more acceptable.

When using 16 bits counters the kernel may not be able to boot
because it has a too high overhead compare to the clockevent period.
Downgrading the rating of 16bits counter won't change anything
to this problem so this patch remove 16 bits counters support
and makes sure that they won't be probed anymore.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index a45f1f1cd040..707808d91bf0 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -84,12 +84,16 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static bool stm32_timer_is_32bits(struct timer_of *to)
+{
+	return readl_relaxed(timer_of_base(to) + TIM_ARR) == ~0UL;
+}
+
 static int __init stm32_clockevent_init(struct device_node *node)
 {
 	struct reset_control *rstc;
-	unsigned long max_delta;
-	int ret, bits, prescaler = 1;
 	struct timer_of *to;
+	int ret;
 
 	to = kzalloc(sizeof(*to), GFP_KERNEL);
 	if (!to)
@@ -118,31 +122,27 @@ static int __init stm32_clockevent_init(struct device_node *node)
 	}
 
 	/* Detect whether the timer is 16 or 32 bits */
-	writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
-	max_delta = readl_relaxed(timer_of_base(to) + TIM_ARR);
-	if (max_delta == ~0U) {
-		prescaler = 1;
-		bits = 32;
-	} else {
-		prescaler = 1024;
-		bits = 16;
+	if (!stm32_timer_is_32bits(to)) {
+		pr_warn("Timer %pOF is a 16 bits timer\n", node);
+		ret = -EINVAL;
+		goto deinit;
 	}
+
 	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
 
-	writel_relaxed(prescaler - 1, timer_of_base(to) + TIM_PSC);
+	writel_relaxed(0, timer_of_base(to) + TIM_PSC);
 	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
 	writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
 	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
 	clockevents_config_and_register(&to->clkevt,
 					timer_of_period(to),
-					MIN_DELTA, max_delta);
-
-	pr_info("%pOF: STM32 clockevent driver initialized (%d bits)\n",
-			node, bits);
+					MIN_DELTA, ~0U);
 
 	return 0;
 
+deinit:
+	timer_of_cleanup(to);
 err:
 	kfree(to);
 	return ret;
-- 
2.15.0

^ permalink raw reply related

* [PATCH v9 4/6] clocksource: stm32: add clocksource support
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

The stm32 timer hardware is currently only used as a clock event device,
but it can be utilized as a clocksource as well.

Implement this by enabling the free running counter in the hardware block
and converting the clock event part from a count down event timer to a
comparator based timer.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 drivers/clocksource/timer-stm32.c | 116 +++++++++++++++++++++++++++++---------
 1 file changed, 88 insertions(+), 28 deletions(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index 707808d91bf0..c9aed2314194 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -16,6 +16,8 @@
 #include <linux/of_irq.h>
 #include <linux/clk.h>
 #include <linux/reset.h>
+#include <linux/sched_clock.h>
+#include <linux/slab.h>
 
 #include "timer-of.h"
 
@@ -23,16 +25,16 @@
 #define TIM_DIER	0x0c
 #define TIM_SR		0x10
 #define TIM_EGR		0x14
+#define TIM_CNT		0x24
 #define TIM_PSC		0x28
 #define TIM_ARR		0x2c
+#define TIM_CCR1	0x34
 
 #define TIM_CR1_CEN	BIT(0)
-#define TIM_CR1_OPM	BIT(3)
+#define TIM_CR1_UDIS	BIT(1)
 #define TIM_CR1_ARPE	BIT(7)
 
-#define TIM_DIER_UIE	BIT(0)
-
-#define TIM_SR_UIF	BIT(0)
+#define TIM_DIER_CC1IE	BIT(1)
 
 #define TIM_EGR_UG	BIT(0)
 
@@ -46,28 +48,44 @@ static int stm32_clock_event_shutdown(struct clock_event_device *evt)
 {
 	struct timer_of *to = to_timer_of(evt);
 
-	writel_relaxed(0, timer_of_base(to) + TIM_CR1);
+	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+
 	return 0;
 }
 
-static int stm32_clock_event_set_periodic(struct clock_event_device *evt)
+static int stm32_clock_event_set_next_event(unsigned long evt,
+					    struct clock_event_device *clkevt)
 {
-	struct timer_of *to = to_timer_of(evt);
+	struct timer_of *to = to_timer_of(clkevt);
+	unsigned long now, next;
 
-	writel_relaxed(timer_of_period(to), timer_of_base(to) + TIM_ARR);
-	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, timer_of_base(to) + TIM_CR1);
+	next = readl_relaxed(timer_of_base(to) + TIM_CNT) + evt;
+	writel_relaxed(next, timer_of_base(to) + TIM_CCR1);
+	now = readl_relaxed(timer_of_base(to) + TIM_CNT);
+
+	if ((next - now) > evt)
+		return -ETIME;
+
+	writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER);
 
 	return 0;
 }
 
-static int stm32_clock_event_set_next_event(unsigned long evt,
-					    struct clock_event_device *clkevt)
+static int stm32_clock_event_set_periodic(struct clock_event_device *evt)
 {
-	struct timer_of *to = to_timer_of(clkevt);
+	struct timer_of *to = to_timer_of(evt);
 
-	writel_relaxed(evt, timer_of_base(to) + TIM_ARR);
-	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_OPM | TIM_CR1_CEN,
-		       timer_of_base(to) + TIM_CR1);
+	return stm32_clock_event_set_next_event(timer_of_period(to), evt);
+}
+
+static int stm32_clock_event_set_oneshot(struct clock_event_device *evt)
+{
+	struct timer_of *to = to_timer_of(evt);
+	unsigned long val;
+
+	val = readl_relaxed(timer_of_base(to) + TIM_CNT);
+	writel_relaxed(val, timer_of_base(to) + TIM_CCR1);
+	writel_relaxed(TIM_DIER_CC1IE, timer_of_base(to) + TIM_DIER);
 
 	return 0;
 }
@@ -79,6 +97,11 @@ static irqreturn_t stm32_clock_event_handler(int irq, void *dev_id)
 
 	writel_relaxed(0, timer_of_base(to) + TIM_SR);
 
+	if (clockevent_state_periodic(evt))
+		stm32_clock_event_set_periodic(evt);
+	else
+		stm32_clock_event_shutdown(evt);
+
 	evt->event_handler(evt);
 
 	return IRQ_HANDLED;
@@ -89,7 +112,48 @@ static bool stm32_timer_is_32bits(struct timer_of *to)
 	return readl_relaxed(timer_of_base(to) + TIM_ARR) == ~0UL;
 }
 
-static int __init stm32_clockevent_init(struct device_node *node)
+static void __init stm32_clockevent_init(struct timer_of *to)
+{
+	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
+
+	clockevents_config_and_register(&to->clkevt,
+					timer_of_rate(to), MIN_DELTA, ~0U);
+}
+
+static void __iomem *stm32_timer_cnt __read_mostly;
+
+static u64 notrace stm32_read_sched_clock(void)
+{
+	return readl_relaxed(stm32_timer_cnt);
+}
+
+static int __init stm32_clocksource_init(struct timer_of *to)
+{
+	writel_relaxed(~0U, timer_of_base(to) + TIM_ARR);
+	writel_relaxed(0, timer_of_base(to) + TIM_PSC);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
+	writel_relaxed(0, timer_of_base(to) + TIM_DIER);
+	writel_relaxed(0, timer_of_base(to) + TIM_SR);
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS,
+		       timer_of_base(to) + TIM_CR1);
+
+	/* Make sure that registers are updated */
+	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
+
+	/* Enable controller */
+	writel_relaxed(TIM_CR1_ARPE | TIM_CR1_UDIS | TIM_CR1_CEN,
+		       timer_of_base(to) + TIM_CR1);
+
+	stm32_timer_cnt = timer_of_base(to) + TIM_CNT;
+	sched_clock_register(stm32_read_sched_clock, 32, timer_of_rate(to));
+
+	return clocksource_mmio_init(stm32_timer_cnt, "stm32_timer",
+				     timer_of_rate(to), 250, 32,
+				     clocksource_mmio_readl_up);
+}
+
+static int __init stm32_timer_init(struct device_node *node)
 {
 	struct reset_control *rstc;
 	struct timer_of *to;
@@ -100,12 +164,13 @@ static int __init stm32_clockevent_init(struct device_node *node)
 		return -ENOMEM;
 
 	to->flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE;
+
 	to->clkevt.name = "stm32_clockevent";
 	to->clkevt.rating = 200;
-	to->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
+	to->clkevt.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC;
 	to->clkevt.set_state_shutdown = stm32_clock_event_shutdown;
 	to->clkevt.set_state_periodic = stm32_clock_event_set_periodic;
-	to->clkevt.set_state_oneshot = stm32_clock_event_shutdown;
+	to->clkevt.set_state_oneshot = stm32_clock_event_set_oneshot;
 	to->clkevt.tick_resume = stm32_clock_event_shutdown;
 	to->clkevt.set_next_event = stm32_clock_event_set_next_event;
 
@@ -128,16 +193,11 @@ static int __init stm32_clockevent_init(struct device_node *node)
 		goto deinit;
 	}
 
-	writel_relaxed(0, timer_of_base(to) + TIM_ARR);
-
-	writel_relaxed(0, timer_of_base(to) + TIM_PSC);
-	writel_relaxed(TIM_EGR_UG, timer_of_base(to) + TIM_EGR);
-	writel_relaxed(TIM_DIER_UIE, timer_of_base(to) + TIM_DIER);
-	writel_relaxed(0, timer_of_base(to) + TIM_SR);
+	ret = stm32_clocksource_init(to);
+	if (ret)
+		goto deinit;
 
-	clockevents_config_and_register(&to->clkevt,
-					timer_of_period(to),
-					MIN_DELTA, ~0U);
+	stm32_clockevent_init(to);
 
 	return 0;
 
@@ -148,4 +208,4 @@ static int __init stm32_clockevent_init(struct device_node *node)
 	return ret;
 }
 
-TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_clockevent_init);
+TIMER_OF_DECLARE(stm32, "st,stm32-timer", stm32_timer_init);
-- 
2.15.0

^ permalink raw reply related

* [PATCH v9 5/6] clocksource: stm32: Update license and copyright
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

Adopt SPDX License Identifier and add STMicroelectronics
copyright

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
---
 drivers/clocksource/timer-stm32.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c
index c9aed2314194..21479c3cfcb9 100644
--- a/drivers/clocksource/timer-stm32.c
+++ b/drivers/clocksource/timer-stm32.c
@@ -1,7 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) Maxime Coquelin 2015
+ * Copyright (C) STMicroelectronics 2017 - All Rights Reserved
  * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
- * License terms:  GNU General Public License (GPL), version 2
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
  *
  * Inspired by time-efm32.c from Uwe Kleine-Koenig
  */
-- 
2.15.0

^ permalink raw reply related

* [PATCH v9 6/6] arm: dts: stm32: remove useless clocksource nodes
From: Benjamin Gaignard @ 2017-12-08 11:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-1-benjamin.gaignard@st.com>

From: Benjamin Gaignard <benjamin.gaignard@linaro.org>

16 bits timers aren't accurate enough to be used as
clocksource, remove them from stm32f4 and stm32f7 devicetree.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 arch/arm/boot/dts/stm32f429.dtsi | 32 --------------------------------
 arch/arm/boot/dts/stm32f746.dtsi | 32 --------------------------------
 2 files changed, 64 deletions(-)

diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 10099df8b73e..b507e04a52c6 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -107,14 +107,6 @@
 			};
 		};
 
-		timer3: timer at 40000400 {
-			compatible = "st,stm32-timer";
-			reg = <0x40000400 0x400>;
-			interrupts = <29>;
-			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM3)>;
-			status = "disabled";
-		};
-
 		timers3: timers at 40000400 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -136,14 +128,6 @@
 			};
 		};
 
-		timer4: timer at 40000800 {
-			compatible = "st,stm32-timer";
-			reg = <0x40000800 0x400>;
-			interrupts = <30>;
-			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM4)>;
-			status = "disabled";
-		};
-
 		timers4: timers at 40000800 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -193,14 +177,6 @@
 			};
 		};
 
-		timer6: timer at 40001000 {
-			compatible = "st,stm32-timer";
-			reg = <0x40001000 0x400>;
-			interrupts = <54>;
-			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM6)>;
-			status = "disabled";
-		};
-
 		timers6: timers at 40001000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -217,14 +193,6 @@
 			};
 		};
 
-		timer7: timer at 40001400 {
-			compatible = "st,stm32-timer";
-			reg = <0x40001400 0x400>;
-			interrupts = <55>;
-			clocks = <&rcc 0 STM32F4_APB1_CLOCK(TIM7)>;
-			status = "disabled";
-		};
-
 		timers7: timers at 40001400 {
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi
index 5f66d151eedb..bb3e262bd456 100644
--- a/arch/arm/boot/dts/stm32f746.dtsi
+++ b/arch/arm/boot/dts/stm32f746.dtsi
@@ -103,14 +103,6 @@
 			};
 		};
 
-		timer3: timer at 40000400 {
-			compatible = "st,stm32-timer";
-			reg = <0x40000400 0x400>;
-			interrupts = <29>;
-			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM3)>;
-			status = "disabled";
-		};
-
 		timers3: timers at 40000400 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -132,14 +124,6 @@
 			};
 		};
 
-		timer4: timer at 40000800 {
-			compatible = "st,stm32-timer";
-			reg = <0x40000800 0x400>;
-			interrupts = <30>;
-			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM4)>;
-			status = "disabled";
-		};
-
 		timers4: timers at 40000800 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -189,14 +173,6 @@
 			};
 		};
 
-		timer6: timer at 40001000 {
-			compatible = "st,stm32-timer";
-			reg = <0x40001000 0x400>;
-			interrupts = <54>;
-			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM6)>;
-			status = "disabled";
-		};
-
 		timers6: timers at 40001000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -213,14 +189,6 @@
 			};
 		};
 
-		timer7: timer at 40001400 {
-			compatible = "st,stm32-timer";
-			reg = <0x40001400 0x400>;
-			interrupts = <55>;
-			clocks = <&rcc 0 STM32F7_APB1_CLOCK(TIM7)>;
-			status = "disabled";
-		};
-
 		timers7: timers at 40001400 {
 			#address-cells = <1>;
 			#size-cells = <0>;
-- 
2.15.0

^ permalink raw reply related

* [PATCH] clkc: zynq: Missing a blank line after declarations.
From: Dhaval Shah @ 2017-12-08 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

Resolved missing a blank line after declarations checkpatch
warnings. Issue found by checkpatch.

Signed-off-by: Dhaval Shah <dhaval23031987@gmail.com>
---
 drivers/clk/zynq/clkc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 88a2cab37f62..1cd4705e405e 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -363,6 +363,7 @@ static void __init zynq_clk_setup(struct device_node *np)
 	/* Peripheral clocks */
 	for (i = fclk0; i <= fclk3; i++) {
 		int enable = !!(fclk_enable & BIT(i - fclk0));
+
 		zynq_clk_register_fclk(i, clk_output_name[i],
 				SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0),
 				periph_parents, enable);
-- 
2.11.0

^ permalink raw reply related

* next/master boot: 270 boots: 35 failed, 213 passed with 20 offline, 2 untried/unknown (next-20171207)
From: Mark Brown @ 2017-12-08 12:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5a29d4c7.4fabdf0a.716d7.8485@mx.google.com>

On Thu, Dec 07, 2017 at 03:54:47PM -0800, kernelci.org bot wrote:

Today's -next failed to boot on peach-pi:

>     exynos_defconfig:
>         exynos5800-peach-pi:
>             lab-collabora: new failure (last pass: next-20171205)

with details at https://kernelci.org/boot/id/5a2a2e7859b5141bc2afa17c/
(including logs and comparisons with other boots, the last good boot was
Wednesday).  It looks like it hangs somewhere late on in boot, the last
output on the console is:

[    4.827139] smsc95xx 3-1.1:1.0 eth0: register 'smsc95xx' at usb-xhci-hcd.3.auto-1.1, smsc95xx USB 2.0 Ethernet, 94:eb:2c:00:03:c0
[    5.781037] dma-pl330 3880000.adma: Loaded driver for PL330 DMAC-241330
[    5.786247] dma-pl330 3880000.adma: 	DBUFF-4x8bytes Num_Chans-6 Num_Peri-16 Num_Events-6
[    5.819200] dma-pl330 3880000.adma: PM domain MAU will not be powered off
[   64.529228] random: crng init done

and there's failures earlier to instantiate the display.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171208/f8b32c38/attachment.sig>

^ permalink raw reply

* next/master boot: 270 boots: 35 failed, 213 passed with 20 offline, 2 untried/unknown (next-20171207)
From: Mark Brown @ 2017-12-08 12:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208122007.GB7606@sirena.org.uk>

On Fri, Dec 08, 2017 at 12:20:07PM +0000, Mark Brown wrote:
> On Thu, Dec 07, 2017 at 03:54:47PM -0800, kernelci.org bot wrote:
> 
> Today's -next failed to boot on peach-pi:
> 
> >     exynos_defconfig:
> >         exynos5800-peach-pi:
> >             lab-collabora: new failure (last pass: next-20171205)
> 
> with details at https://kernelci.org/boot/id/5a2a2e7859b5141bc2afa17c/
> (including logs and comparisons with other boots, the last good boot was
> Wednesday).  It looks like it hangs somewhere late on in boot, the last
> output on the console is:
> 
> [    4.827139] smsc95xx 3-1.1:1.0 eth0: register 'smsc95xx' at usb-xhci-hcd.3.auto-1.1, smsc95xx USB 2.0 Ethernet, 94:eb:2c:00:03:c0
> [    5.781037] dma-pl330 3880000.adma: Loaded driver for PL330 DMAC-241330
> [    5.786247] dma-pl330 3880000.adma: 	DBUFF-4x8bytes Num_Chans-6 Num_Peri-16 Num_Events-6
> [    5.819200] dma-pl330 3880000.adma: PM domain MAU will not be powered off
> [   64.529228] random: crng init done
> 
> and there's failures earlier to instantiate the display.

I just noticed that further up the log there's a lockdep splat with a
conflict between the genpd and clock API locking - an ABBA issue with
genpd->mlock and the clock API prepare_lock.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20171208/8ebfabce/attachment.sig>

^ permalink raw reply

* [RFC PATCH 2/5] perf jevents: add support for arch recommended events
From: Jiri Olsa @ 2017-12-08 12:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c46d07bc-a6f0-1b01-0595-a615781f8cff@huawei.com>

On Wed, Dec 06, 2017 at 03:20:14PM +0000, John Garry wrote:
> On 06/12/2017 13:36, Jiri Olsa wrote:
> > On Wed, Dec 06, 2017 at 12:13:16AM +0800, John Garry wrote:
> > > For some architectures (like arm64), there are architecture-
> > > defined recommended events. Vendors may not be obliged to
> > > follow the recommendation and may implement their own pmu
> > > event for a specific event code.
> > > 
> > > This patch adds support for parsing events from arch-defined
> > > recommended JSONs, and then fixing up vendor events when
> > > they have implemented these events as recommended.
> > 
> > in the previous patch you added the vendor support, so
> > you have arch|vendor|platform key for the event list
> > and perf have the most current/local event list
> > 
> > why would you need to fix it? if there's new event list,
> > the table gets updated, perf is rebuilt.. I'm clearly
> > missing something ;-)
> 
> The 2 patches are quite separate. In the first patch, I just added support
> for the vendor subdirectory.
> 
> So this patch is not related to rebuilding when adding a new event list or
> dependency checking.
> 
> Here we are trying to allow the vendor to just specify that an event is
> supported as standard in their platform, without duplicating all the
> standard event fields in their JSON. When processing the vendor JSONs, the
> jevents tool can figure which events are standard and create the proper
> event entries in the pmu events table, referencing the architecture JSON.

I think we should keep this simple and mangle this with some pointer logic

now you have arch/vendor/platform directory structure.. why don't
you add events for every such directory? I understand there will
be duplications, but we already have them for other archs and it's
not big deal:

	[jolsa at krava perf]$ grep -r L2_RQSTS.DEMAND_DATA_RD_MISS pmu-events/arch/*
	pmu-events/arch/x86/broadwell/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/haswell/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/broadwellde/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/haswellx/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/skylake/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/skylakex/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",
	pmu-events/arch/x86/broadwellx/cache.json:        "EventName": "L2_RQSTS.DEMAND_DATA_RD_MISS",

thanks,
jirka

^ permalink raw reply

* [RFC PATCH 2/5] perf jevents: add support for arch recommended events
From: Jiri Olsa @ 2017-12-08 12:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <f58001e9-86fa-c6e6-b9c7-fb748d340da1@huawei.com>

On Wed, Dec 06, 2017 at 02:40:10PM +0000, John Garry wrote:
> On 06/12/2017 13:37, Jiri Olsa wrote:
> > On Wed, Dec 06, 2017 at 12:13:16AM +0800, John Garry wrote:
> > 
> > SNIP
> > 
> > > ---
> > >  tools/perf/pmu-events/jevents.c | 215 ++++++++++++++++++++++++++++++++++++----
> > >  1 file changed, 198 insertions(+), 17 deletions(-)
> > > 
> > > diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
> > > index a0d489e..a820ed4 100644
> > > --- a/tools/perf/pmu-events/jevents.c
> > > +++ b/tools/perf/pmu-events/jevents.c
> > > @@ -42,6 +42,7 @@
> > >  #include <dirent.h>
> > >  #include <sys/time.h>			/* getrlimit */
> > >  #include <sys/resource.h>		/* getrlimit */
> > > +#include <sys/queue.h>
> > >  #include <ftw.h>
> > >  #include <sys/stat.h>
> > >  #include "jsmn.h"
> > > @@ -366,6 +367,94 @@ static int print_events_table_entry(void *data, char *name, char *event,
> > >  	return 0;
> > >  }
> > > 
> > > +struct event_struct {
> > > +	char *name;
> > > +	char *event;
> > > +	char *desc;
> > > +	char *long_desc;
> > > +	char *pmu;
> > > +	char *unit;
> > > +	char *perpkg;
> > > +	char *metric_expr;
> > > +	char *metric_name;
> > > +	char *metric_group;
> > > +	LIST_ENTRY(event_struct) list;
> > 
> > is there any reason you don't use the 'struct list_head' ?
> > I dont think we want another thingie involved for lists
> 
> Hi jirka,
> 
> The linux kernel headers are not used for jevents tool. I would rather use
> them if possible...

should be as easy as adding  #include <linux/list.h> ;-)

it's heavily used within perf and I'm pretty sure we want
to keep around just one way of doing lists

thanks,
jirka

^ permalink raw reply

* next/master boot: 270 boots: 35 failed, 213 passed with 20 offline, 2 untried/unknown (next-20171207)
From: Krzysztof Kozlowski @ 2017-12-08 12:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208122703.GC7606@sirena.org.uk>

On Fri, Dec 8, 2017 at 1:27 PM, Mark Brown <broonie@kernel.org> wrote:
> On Fri, Dec 08, 2017 at 12:20:07PM +0000, Mark Brown wrote:
>> On Thu, Dec 07, 2017 at 03:54:47PM -0800, kernelci.org bot wrote:
>>
>> Today's -next failed to boot on peach-pi:
>>
>> >     exynos_defconfig:
>> >         exynos5800-peach-pi:
>> >             lab-collabora: new failure (last pass: next-20171205)
>>
>> with details at https://kernelci.org/boot/id/5a2a2e7859b5141bc2afa17c/
>> (including logs and comparisons with other boots, the last good boot was
>> Wednesday).  It looks like it hangs somewhere late on in boot, the last
>> output on the console is:
>>
>> [    4.827139] smsc95xx 3-1.1:1.0 eth0: register 'smsc95xx' at usb-xhci-hcd.3.auto-1.1, smsc95xx USB 2.0 Ethernet, 94:eb:2c:00:03:c0
>> [    5.781037] dma-pl330 3880000.adma: Loaded driver for PL330 DMAC-241330
>> [    5.786247] dma-pl330 3880000.adma:        DBUFF-4x8bytes Num_Chans-6 Num_Peri-16 Num_Events-6
>> [    5.819200] dma-pl330 3880000.adma: PM domain MAU will not be powered off
>> [   64.529228] random: crng init done
>>
>> and there's failures earlier to instantiate the display.
>
> I just noticed that further up the log there's a lockdep splat with a
> conflict between the genpd and clock API locking - an ABBA issue with
> genpd->mlock and the clock API prepare_lock.

+Cc Marek Szyprowski,

The lockdep issue and display failures (including regulator warning)
were present for some time. They also appear in boot log for
next-20171206 (https://storage.kernelci.org/next/master/next-20171206/arm/exynos_defconfig/lab-collabora/boot-exynos5800-peach-pi.html).
The difference is that 20171208 hangs on "random: crng init done"
which did not appear before at all.

The only recent changes in samsung-soc tree which could affect Exynos5800 is
 - ARM: dts: exynos: Add audio power domain support to Exynos542x SoCs
https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git/commit/?h=next/dt&id=528832d4c01a2b400775df95fe8d363cf4c5230f
 - ARM: dts: exynos: Add CPU perf counters to Exynos54xx boards
https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git/commit/?h=next/dt&id=c4f2fc00defc65950dfabce7a4c70cd2a289111d

But both of them were present in next for few days so they should hit
20171206 as well.

Maybe the issue comes from different subsystem?

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH] media: v4l: xilinx: Use SPDX-License-Identifier
From: Dhaval Shah @ 2017-12-08 12:35 UTC (permalink / raw)
  To: linux-arm-kernel

SPDX-License-Identifier is used for the Xilinx Video IP and
related drivers.

Signed-off-by: Dhaval Shah <dhaval23031987@gmail.com>
---
 drivers/media/platform/xilinx/xilinx-dma.c  | 5 +----
 drivers/media/platform/xilinx/xilinx-dma.h  | 5 +----
 drivers/media/platform/xilinx/xilinx-tpg.c  | 5 +----
 drivers/media/platform/xilinx/xilinx-vip.c  | 5 +----
 drivers/media/platform/xilinx/xilinx-vip.h  | 5 +----
 drivers/media/platform/xilinx/xilinx-vipp.c | 5 +----
 drivers/media/platform/xilinx/xilinx-vipp.h | 5 +----
 drivers/media/platform/xilinx/xilinx-vtc.c  | 5 +----
 drivers/media/platform/xilinx/xilinx-vtc.h  | 5 +----
 9 files changed, 9 insertions(+), 36 deletions(-)

diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 522cdfdd3345..2e5daf7dba1a 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video DMA
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/dma/xilinx_dma.h>
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index e95d136c153a..5aec4d17eb21 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video DMA
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIP_DMA_H__
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index 9c49d1d10bee..20a68a65602b 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Test Pattern Generator
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/device.h>
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
index 311259129504..5f7efa9f093e 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.c
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Core
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/clk.h>
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
index 42fee2026815..ba939dd52818 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.h
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Core
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIP_H__
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index d881cf09876d..cb9ab2c15952 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Composite Device
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/list.h>
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
index faf6b6e80b3b..39daa030679e 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.h
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video IP Composite Device
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VIPP_H__
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c
index 01c750edcac5..0ae0208d7529 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.c
+++ b/drivers/media/platform/xilinx/xilinx-vtc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video Timing Controller
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/clk.h>
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h
index e1bb2cfcf428..90cf44245283 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.h
+++ b/drivers/media/platform/xilinx/xilinx-vtc.h
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Xilinx Video Timing Controller
  *
@@ -6,10 +7,6 @@
  *
  * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
  *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef __XILINX_VTC_H__
-- 
2.11.0

^ permalink raw reply related

* [PATCH v9 3/6] clocksource: stm32: only use 32 bits timers
From: Daniel Lezcano @ 2017-12-08 12:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208113250.359-4-benjamin.gaignard@st.com>

On 08/12/2017 12:32, Benjamin Gaignard wrote:
> From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> 
> The clock driving counters is at 90MHz so the maximum period
> for 16 bis counters is around 728us (2^16 / 90.000.000).
> For 32 bits counters this period is close 47 secondes which is
> more acceptable.
> 
> When using 16 bits counters the kernel may not be able to boot
> because it has a too high overhead compare to the clockevent period.
> Downgrading the rating of 16bits counter won't change anything
> to this problem so this patch remove 16 bits counters support
> and makes sure that they won't be probed anymore.

Benjamin,

there is an inconsistency in this description and the patchset. This is
why it is so confusing to review and understand the purpose.

Why are you preventing the clockevents to work with 16bits while the
issue is related to the clocksource you introduce in the next patch ?

Also, why are you removing the DT nodes ?

Accept to register the clocksource only if it is a 32bits timer. Let the
clockevents to register themselves and have the rating to sort out the
this. I do believe that is what Thomas asked you the first time.

You can keep the hardware description in the DT and boot gracefully with
the first 32bits timer succeeding the init.

Take the time to think about it, comment and let's reach an agreement
before you send another version, I'm tired to review again and again
these stm32 timers.

Thanks.

  -- Daniel




-- 
 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* [PATCH] i2c: core: Use GPIO descriptors for recovery
From: Linus Walleij @ 2017-12-08 13:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171208105010.xn6m4bl3hiaxhizq@ninjato>

On Fri, Dec 8, 2017 at 11:50 AM, Wolfram Sang <wsa@the-dreams.de> wrote:
> On Fri, Dec 08, 2017 at 11:20:02AM +0100, Linus Walleij wrote:
>> The I2C core contains code for handling a fallback recovery
>> using GPIO when a piece of I2C hardware fails in duty.
>>
>> This code passes GPIO numbers from the global GPIO
>> numberspace around and we want to get rid of this and use
>> GPIO descriptors associated with the devices.
>>
>> After some digging it turns out that there are two users
>> of the mechanism in the entire kernel:
>>
>> - i.MX that simply define "scl-gpios" and "sda-gpios" in
>>   the device tree which is already creating descriptors
>>   associated with the device, that we can pick up and use.
>>
>> - Two DaVinci boards that pass the SCL and SDA GPIOs using
>>   custom platform data.
>>
>> Refactor the core to grab the SCL and SDA GPIO descriptors
>> on-demand when doing recovery, and release them when
>> recovery is done. Grab the named descriptors "scl" and
>> "sda" which will make the i.MX method work out of the
>> box.
>>
>> Augment the two DaVinci board files to pass descriptors
>> using static tables.
>>
>> Cc: Shawn Guo <shawnguo@kernel.org>
>> Cc: Sascha Hauer <kernel@pengutronix.de>
>> Cc: Fabio Estevam <fabio.estevam@nxp.com>
>> Cc: Sekhar Nori <nsekhar@ti.com>
>> Cc: Kevin Hilman <khilman@kernel.org>
>> Cc: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>
> We have this in i2c/for-next:
>
> 3991c5c80beaf7 ("i2c: Switch to using gpiod interface for gpio bus recovery")
>
> Sorry, I just noticed you were not on CC. I wrongly remembered you took
> part in that discussion, too.

Haha OK no problem, I'll go review the other patch.

Yours,
Linus Walleij

^ permalink raw reply


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