* [PATCH 1/2] efi: add support for seeding the RNG from a UEFI config table
From: Ard Biesheuvel @ 2016-10-19 11:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019110926.GG9616@leverpostej>
On 19 October 2016 at 12:09, Mark Rutland <mark.rutland@arm.com> wrote:
> Hi Ard,
>
> On Thu, Oct 06, 2016 at 11:27:25AM +0100, Ard Biesheuvel wrote:
>> Specify a Linux specific UEFI configuration table that carries some
>> random bits, and use the contents during early boot to seed the kernel's
>> random number generator. This allows much strong random numbers to be
>> generated early on.
>>
>> The entropy is fed to the kernel using add_device_randomness(), which is
>> documented as being appropriate for being called very early.
>>
>> Note that the config table could be generated by the EFI stub or by any
>> other UEFI driver or application (e.g., GRUB), but the random seed table
>> GUID and the associated functionality should be considered an internal
>> kernel interface (unless it is promoted to ABI later on)
>
> What does this mean for kexec? Won't each successive kernel look for the
> table and find the same seed?
>
Yes. Whether this is a problem or not is context dependent: for things
like kdump, I don't think anyone cares. For other cases, having some
seed may still be better than having no seed at all.
It does mean, however, that we have to preserve the memory this table
points to for kexec boots.
> I think to some extent this mush be treated as an ABI, given cases like
> kexec.
>
Perhaps, yes. That would also allow GRUB or other EFI aware
bootloaders to generate the seed.
^ permalink raw reply
* [RFC PATCH] mtd: nand: Add OX820 NAND Support
From: Boris Brezillon @ 2016-10-19 11:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <37a5b543-e564-a496-d5cf-c215e798839f@baylibre.com>
On Wed, 19 Oct 2016 11:29:59 +0200
Neil Armstrong <narmstrong@baylibre.com> wrote:
> Hi Boris,
>
> On 10/18/2016 10:17 PM, Boris Brezillon wrote:
> > Hi Neil,
> >
> > On Tue, 18 Oct 2016 11:09:27 +0200
> > Neil Armstrong <narmstrong@baylibre.com> wrote:
> >
> >> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> >> This is a simple memory mapped NAND controller with single chip select and
> >> software ECC.
> >>
> >> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> >> ---
> >> .../devicetree/bindings/mtd/oxnas-nand.txt | 24 ++++
> >> drivers/mtd/nand/Kconfig | 5 +
> >> drivers/mtd/nand/Makefile | 1 +
> >> drivers/mtd/nand/oxnas_nand.c | 144 +++++++++++++++++++++
> >> 4 files changed, 174 insertions(+)
> >> create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >> create mode 100644 drivers/mtd/nand/oxnas_nand.c
> >>
> >> diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >> new file mode 100644
> >> index 0000000..83b684d
> >> --- /dev/null
> >> +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> >> @@ -0,0 +1,24 @@
> >> +* Oxford Semiconductor OXNAS NAND Controller
> >> +
> >> +Please refer to nand.txt for generic information regarding MTD NAND bindings.
> >> +
> >> +Required properties:
> >> + - compatible: "oxsemi,ox820-nand"
> >> + - reg: Base address and length for NAND mapped memory.
> >> +
> >> +Optional Properties:
> >> + - clocks: phandle to the NAND gate clock if needed.
> >> + - resets: phandle to the NAND reset control if needed.
> >> +
> >> +Example:
> >> +
> >> +nand: nand at 41000000 {
> >> + compatible = "oxsemi,ox820-nand";
> >> + reg = <0x41000000 0x100000>;
> >> + nand-ecc-mode = "soft";
> >> + clocks = <&stdclk CLK_820_NAND>;
> >> + resets = <&reset RESET_NAND>;
> >> + #address-cells = <1>;
> >> + #size-cells = <1>;
> >> + status = "disabled";
> >> +};
> >
> > Can you switch to new DT representation for NAND controllers, with one
> > node for the NAND controller and NAND devices connected to this NAND
> > controller defined as sub-nodes of this NAND controller [1]?
>
> Yes, I was wondering if this existed... my bad, next time I will search further.
No problem. That's what reviews are here for ;-).
[...]
> >> diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
[...]
> >> +
> >> +/* nand commands */
> >> +#define NAND_CMD_ALE BIT(18)
> >> +#define NAND_CMD_CLE BIT(19)
> >> +#define NAND_CMD_CS 0
> >
> > I guess this is zero here because you only support connecting a NAND to
> > CS0.
> > It's probably something like
> >
> > OX820_NAND_CS(x) ((x) << CS_FIELD_SHIFT)
>
> The hardware seems to be able to drive multiple chip selects, but no implementation does this.
> We will stick to CS0 only here for test reasons.
Then no need to define this _CS flag.
[...]
> >> + data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
> >> + data->chip.chip_delay = 30;
> >> + data->chip.ecc.mode = NAND_ECC_SOFT;
> >> + data->chip.ecc.algo = NAND_ECC_HAMMING;
> >
> > Probably a good idea to support soft ECC as well...
I meant BCH, not soft :-).
>
> This was taken from plat_nand.c, I was not sure if it was necessary, will remove this and rely on DT attributes.
Yes, that's probably the best solution.
Regards,
Boris
^ permalink raw reply
* [PATCH 1/2] efi: add support for seeding the RNG from a UEFI config table
From: Mark Rutland @ 2016-10-19 11:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475749646-10844-2-git-send-email-ard.biesheuvel@linaro.org>
Hi Ard,
On Thu, Oct 06, 2016 at 11:27:25AM +0100, Ard Biesheuvel wrote:
> Specify a Linux specific UEFI configuration table that carries some
> random bits, and use the contents during early boot to seed the kernel's
> random number generator. This allows much strong random numbers to be
> generated early on.
>
> The entropy is fed to the kernel using add_device_randomness(), which is
> documented as being appropriate for being called very early.
>
> Note that the config table could be generated by the EFI stub or by any
> other UEFI driver or application (e.g., GRUB), but the random seed table
> GUID and the associated functionality should be considered an internal
> kernel interface (unless it is promoted to ABI later on)
What does this mean for kexec? Won't each successive kernel look for the
table and find the same seed?
I think to some extent this mush be treated as an ABI, given cases like
kexec.
Thanks,
Mark.
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> drivers/firmware/efi/efi.c | 26 ++++++++++++++++++++
> include/linux/efi.h | 8 ++++++
> 2 files changed, 34 insertions(+)
>
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 1ac199cd75e7..c8ae40f9b674 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -24,6 +24,7 @@
> #include <linux/of_fdt.h>
> #include <linux/io.h>
> #include <linux/platform_device.h>
> +#include <linux/random.h>
> #include <linux/slab.h>
> #include <linux/acpi.h>
> #include <linux/ucs2_string.h>
> @@ -48,6 +49,7 @@ struct efi __read_mostly efi = {
> .esrt = EFI_INVALID_TABLE_ADDR,
> .properties_table = EFI_INVALID_TABLE_ADDR,
> .mem_attr_table = EFI_INVALID_TABLE_ADDR,
> + .rng_seed = EFI_INVALID_TABLE_ADDR,
> };
> EXPORT_SYMBOL(efi);
>
> @@ -438,6 +440,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
> {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
> {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
> {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
> + {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
> {NULL_GUID, NULL, NULL},
> };
>
> @@ -499,6 +502,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
> pr_cont("\n");
> set_bit(EFI_CONFIG_TABLES, &efi.flags);
>
> + if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
> + struct linux_efi_random_seed *seed;
> + u32 size = 0;
> +
> + seed = early_memremap(efi.rng_seed, sizeof(*seed));
> + if (seed != NULL) {
> + size = seed->size;
> + early_memunmap(seed, sizeof(*seed));
> + } else {
> + pr_err("Could not map UEFI random seed!\n");
> + }
> + if (size > 0) {
> + seed = early_memremap(efi.rng_seed,
> + sizeof(*seed) + size);
> + if (seed != NULL) {
> + add_device_randomness(seed->bits, seed->size);
> + early_memunmap(seed, sizeof(*seed) + size);
> + } else {
> + pr_err("Could not map UEFI random seed!\n");
> + }
> + }
> + }
> +
> /* Parse the EFI Properties table if it exists */
> if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
> efi_properties_table_t *tbl;
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 2d089487d2da..85e28b138cdd 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -599,6 +599,7 @@ void efi_native_runtime_setup(void);
> */
> #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
> #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
> +#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
>
> typedef struct {
> efi_guid_t guid;
> @@ -872,6 +873,7 @@ extern struct efi {
> unsigned long esrt; /* ESRT table */
> unsigned long properties_table; /* properties table */
> unsigned long mem_attr_table; /* memory attributes table */
> + unsigned long rng_seed; /* UEFI firmware random seed */
> efi_get_time_t *get_time;
> efi_set_time_t *set_time;
> efi_get_wakeup_time_t *get_wakeup_time;
> @@ -1493,4 +1495,10 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table,
> struct efi_boot_memmap *map,
> void *priv,
> efi_exit_boot_map_processing priv_func);
> +
> +struct linux_efi_random_seed {
> + u32 size;
> + u8 bits[];
> +};
> +
> #endif /* _LINUX_EFI_H */
> --
> 2.7.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-efi" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH 1/2] efi: add support for seeding the RNG from a UEFI config table
From: Matt Fleming @ 2016-10-19 11:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1475749646-10844-2-git-send-email-ard.biesheuvel@linaro.org>
(CC'ing other potentially interested randomness folks)
On Thu, 06 Oct, at 11:27:25AM, Ard Biesheuvel wrote:
> Specify a Linux specific UEFI configuration table that carries some
> random bits, and use the contents during early boot to seed the kernel's
> random number generator. This allows much strong random numbers to be
> generated early on.
>
> The entropy is fed to the kernel using add_device_randomness(), which is
> documented as being appropriate for being called very early.
>
> Note that the config table could be generated by the EFI stub or by any
> other UEFI driver or application (e.g., GRUB), but the random seed table
> GUID and the associated functionality should be considered an internal
> kernel interface (unless it is promoted to ABI later on)
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> drivers/firmware/efi/efi.c | 26 ++++++++++++++++++++
> include/linux/efi.h | 8 ++++++
> 2 files changed, 34 insertions(+)
This series looks fine to me. I'm leaving the patch below for the
benefit of the Ted and Kees.
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index 1ac199cd75e7..c8ae40f9b674 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -24,6 +24,7 @@
> #include <linux/of_fdt.h>
> #include <linux/io.h>
> #include <linux/platform_device.h>
> +#include <linux/random.h>
> #include <linux/slab.h>
> #include <linux/acpi.h>
> #include <linux/ucs2_string.h>
> @@ -48,6 +49,7 @@ struct efi __read_mostly efi = {
> .esrt = EFI_INVALID_TABLE_ADDR,
> .properties_table = EFI_INVALID_TABLE_ADDR,
> .mem_attr_table = EFI_INVALID_TABLE_ADDR,
> + .rng_seed = EFI_INVALID_TABLE_ADDR,
> };
> EXPORT_SYMBOL(efi);
>
> @@ -438,6 +440,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
> {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
> {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
> {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
> + {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
> {NULL_GUID, NULL, NULL},
> };
>
> @@ -499,6 +502,29 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
> pr_cont("\n");
> set_bit(EFI_CONFIG_TABLES, &efi.flags);
>
> + if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
> + struct linux_efi_random_seed *seed;
> + u32 size = 0;
> +
> + seed = early_memremap(efi.rng_seed, sizeof(*seed));
> + if (seed != NULL) {
> + size = seed->size;
> + early_memunmap(seed, sizeof(*seed));
> + } else {
> + pr_err("Could not map UEFI random seed!\n");
> + }
> + if (size > 0) {
> + seed = early_memremap(efi.rng_seed,
> + sizeof(*seed) + size);
> + if (seed != NULL) {
> + add_device_randomness(seed->bits, seed->size);
> + early_memunmap(seed, sizeof(*seed) + size);
> + } else {
> + pr_err("Could not map UEFI random seed!\n");
> + }
> + }
> + }
> +
> /* Parse the EFI Properties table if it exists */
> if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
> efi_properties_table_t *tbl;
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 2d089487d2da..85e28b138cdd 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -599,6 +599,7 @@ void efi_native_runtime_setup(void);
> */
> #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
> #define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
> +#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
>
> typedef struct {
> efi_guid_t guid;
> @@ -872,6 +873,7 @@ extern struct efi {
> unsigned long esrt; /* ESRT table */
> unsigned long properties_table; /* properties table */
> unsigned long mem_attr_table; /* memory attributes table */
> + unsigned long rng_seed; /* UEFI firmware random seed */
> efi_get_time_t *get_time;
> efi_set_time_t *set_time;
> efi_get_wakeup_time_t *get_wakeup_time;
> @@ -1493,4 +1495,10 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table,
> struct efi_boot_memmap *map,
> void *priv,
> efi_exit_boot_map_processing priv_func);
> +
> +struct linux_efi_random_seed {
> + u32 size;
> + u8 bits[];
> +};
> +
> #endif /* _LINUX_EFI_H */
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH 2/2] arm64: percpu: rewrite ll/sc loops in assembly
From: Will Deacon @ 2016-10-19 10:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476874784-16214-1-git-send-email-will.deacon@arm.com>
Writing the outer loop of an LL/SC sequence using do {...} while
constructs potentially allows the compiler to hoist memory accesses
between the STXR and the branch back to the LDXR. On CPUs that do not
guarantee forward progress of LL/SC loops when faced with memory
accesses to the same ERG (up to 2k) between the failed STXR and the
branch back, we may end up livelocking.
This patch avoids this issue in our percpu atomics by rewriting the
outer loop as part of the LL/SC inline assembly block.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/percpu.h | 120 +++++++++++++++++++---------------------
1 file changed, 56 insertions(+), 64 deletions(-)
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 2fee2f59288c..5394c8405e66 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -44,48 +44,44 @@ static inline unsigned long __percpu_##op(void *ptr, \
\
switch (size) { \
case 1: \
- do { \
- asm ("//__per_cpu_" #op "_1\n" \
- "ldxrb %w[ret], %[ptr]\n" \
+ asm ("//__per_cpu_" #op "_1\n" \
+ "1: ldxrb %w[ret], %[ptr]\n" \
#asm_op " %w[ret], %w[ret], %w[val]\n" \
- "stxrb %w[loop], %w[ret], %[ptr]\n" \
- : [loop] "=&r" (loop), [ret] "=&r" (ret), \
- [ptr] "+Q"(*(u8 *)ptr) \
- : [val] "Ir" (val)); \
- } while (loop); \
+ " stxrb %w[loop], %w[ret], %[ptr]\n" \
+ " cbnz %w[loop], 1b" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u8 *)ptr) \
+ : [val] "Ir" (val)); \
break; \
case 2: \
- do { \
- asm ("//__per_cpu_" #op "_2\n" \
- "ldxrh %w[ret], %[ptr]\n" \
+ asm ("//__per_cpu_" #op "_2\n" \
+ "1: ldxrh %w[ret], %[ptr]\n" \
#asm_op " %w[ret], %w[ret], %w[val]\n" \
- "stxrh %w[loop], %w[ret], %[ptr]\n" \
- : [loop] "=&r" (loop), [ret] "=&r" (ret), \
- [ptr] "+Q"(*(u16 *)ptr) \
- : [val] "Ir" (val)); \
- } while (loop); \
+ " stxrh %w[loop], %w[ret], %[ptr]\n" \
+ " cbnz %w[loop], 1b" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u16 *)ptr) \
+ : [val] "Ir" (val)); \
break; \
case 4: \
- do { \
- asm ("//__per_cpu_" #op "_4\n" \
- "ldxr %w[ret], %[ptr]\n" \
+ asm ("//__per_cpu_" #op "_4\n" \
+ "1: ldxr %w[ret], %[ptr]\n" \
#asm_op " %w[ret], %w[ret], %w[val]\n" \
- "stxr %w[loop], %w[ret], %[ptr]\n" \
- : [loop] "=&r" (loop), [ret] "=&r" (ret), \
- [ptr] "+Q"(*(u32 *)ptr) \
- : [val] "Ir" (val)); \
- } while (loop); \
+ " stxr %w[loop], %w[ret], %[ptr]\n" \
+ " cbnz %w[loop], 1b" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u32 *)ptr) \
+ : [val] "Ir" (val)); \
break; \
case 8: \
- do { \
- asm ("//__per_cpu_" #op "_8\n" \
- "ldxr %[ret], %[ptr]\n" \
+ asm ("//__per_cpu_" #op "_8\n" \
+ "1: ldxr %[ret], %[ptr]\n" \
#asm_op " %[ret], %[ret], %[val]\n" \
- "stxr %w[loop], %[ret], %[ptr]\n" \
- : [loop] "=&r" (loop), [ret] "=&r" (ret), \
- [ptr] "+Q"(*(u64 *)ptr) \
- : [val] "Ir" (val)); \
- } while (loop); \
+ " stxr %w[loop], %[ret], %[ptr]\n" \
+ " cbnz %w[loop], 1b" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u64 *)ptr) \
+ : [val] "Ir" (val)); \
break; \
default: \
BUILD_BUG(); \
@@ -150,44 +146,40 @@ static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
switch (size) {
case 1:
- do {
- asm ("//__percpu_xchg_1\n"
- "ldxrb %w[ret], %[ptr]\n"
- "stxrb %w[loop], %w[val], %[ptr]\n"
- : [loop] "=&r"(loop), [ret] "=&r"(ret),
- [ptr] "+Q"(*(u8 *)ptr)
- : [val] "r" (val));
- } while (loop);
+ asm ("//__percpu_xchg_1\n"
+ "1: ldxrb %w[ret], %[ptr]\n"
+ " stxrb %w[loop], %w[val], %[ptr]\n"
+ " cbnz %w[loop], 1b"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u8 *)ptr)
+ : [val] "r" (val));
break;
case 2:
- do {
- asm ("//__percpu_xchg_2\n"
- "ldxrh %w[ret], %[ptr]\n"
- "stxrh %w[loop], %w[val], %[ptr]\n"
- : [loop] "=&r"(loop), [ret] "=&r"(ret),
- [ptr] "+Q"(*(u16 *)ptr)
- : [val] "r" (val));
- } while (loop);
+ asm ("//__percpu_xchg_2\n"
+ "1: ldxrh %w[ret], %[ptr]\n"
+ " stxrh %w[loop], %w[val], %[ptr]\n"
+ " cbnz %w[loop], 1b"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u16 *)ptr)
+ : [val] "r" (val));
break;
case 4:
- do {
- asm ("//__percpu_xchg_4\n"
- "ldxr %w[ret], %[ptr]\n"
- "stxr %w[loop], %w[val], %[ptr]\n"
- : [loop] "=&r"(loop), [ret] "=&r"(ret),
- [ptr] "+Q"(*(u32 *)ptr)
- : [val] "r" (val));
- } while (loop);
+ asm ("//__percpu_xchg_4\n"
+ "1: ldxr %w[ret], %[ptr]\n"
+ " stxr %w[loop], %w[val], %[ptr]\n"
+ " cbnz %w[loop], 1b"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u32 *)ptr)
+ : [val] "r" (val));
break;
case 8:
- do {
- asm ("//__percpu_xchg_8\n"
- "ldxr %[ret], %[ptr]\n"
- "stxr %w[loop], %[val], %[ptr]\n"
- : [loop] "=&r"(loop), [ret] "=&r"(ret),
- [ptr] "+Q"(*(u64 *)ptr)
- : [val] "r" (val));
- } while (loop);
+ asm ("//__percpu_xchg_8\n"
+ "1: ldxr %[ret], %[ptr]\n"
+ " stxr %w[loop], %[val], %[ptr]\n"
+ " cbnz %w[loop], 1b"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u64 *)ptr)
+ : [val] "r" (val));
break;
default:
BUILD_BUG();
--
2.1.4
^ permalink raw reply related
* [PATCH 1/2] arm64: swp emulation: bound LL/SC retries before rescheduling
From: Will Deacon @ 2016-10-19 10:59 UTC (permalink / raw)
To: linux-arm-kernel
If a CPU does not implement a global monitor for certain memory types,
then userspace can attempt a kernel DoS by issuing SWP instructions
targetting the problematic memory (for example, a framebuffer mapped
with non-cacheable attributes).
The SWP emulation code protects against these sorts of attacks by
checking for pending signals and potentially rescheduling when the STXR
instruction fails during the emulation. Whilst this is good for avoiding
livelock, it harms emulation of legitimate SWP instructions on CPUs
where forward progress is not guaranteed if there are memory accesses to
the same reservation granule (up to 2k) between the failing STXR and
the retry of the LDXR.
This patch solves the problem by retrying the STXR a bounded number of
times (4) before breaking out of the LL/SC loop and looking for
something else to do.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/armv8_deprecated.c | 36 ++++++++++++++++++++++--------------
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 42ffdb54e162..b0988bb1bf64 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -280,35 +280,43 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
/*
* Error-checking SWP macros implemented using ldxr{b}/stxr{b}
*/
-#define __user_swpX_asm(data, addr, res, temp, B) \
+
+/* Arbitrary constant to ensure forward-progress of the LL/SC loop */
+#define __SWP_LL_SC_LOOPS 4
+
+#define __user_swpX_asm(data, addr, res, temp, temp2, B) \
__asm__ __volatile__( \
+ " mov %w3, %w7\n" \
ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
- "0: ldxr"B" %w2, [%3]\n" \
- "1: stxr"B" %w0, %w1, [%3]\n" \
+ "0: ldxr"B" %w2, [%4]\n" \
+ "1: stxr"B" %w0, %w1, [%4]\n" \
" cbz %w0, 2f\n" \
- " mov %w0, %w4\n" \
+ " sub %w3, %w3, #1\n" \
+ " cbnz %w3, 0b\n" \
+ " mov %w0, %w5\n" \
" b 3f\n" \
"2:\n" \
" mov %w1, %w2\n" \
"3:\n" \
" .pushsection .fixup,\"ax\"\n" \
" .align 2\n" \
- "4: mov %w0, %w5\n" \
+ "4: mov %w0, %w6\n" \
" b 3b\n" \
" .popsection" \
_ASM_EXTABLE(0b, 4b) \
_ASM_EXTABLE(1b, 4b) \
ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \
CONFIG_ARM64_PAN) \
- : "=&r" (res), "+r" (data), "=&r" (temp) \
- : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
+ : "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
+ : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \
+ "i" (__SWP_LL_SC_LOOPS) \
: "memory")
-#define __user_swp_asm(data, addr, res, temp) \
- __user_swpX_asm(data, addr, res, temp, "")
-#define __user_swpb_asm(data, addr, res, temp) \
- __user_swpX_asm(data, addr, res, temp, "b")
+#define __user_swp_asm(data, addr, res, temp, temp2) \
+ __user_swpX_asm(data, addr, res, temp, temp2, "")
+#define __user_swpb_asm(data, addr, res, temp, temp2) \
+ __user_swpX_asm(data, addr, res, temp, temp2, "b")
/*
* Bit 22 of the instruction encoding distinguishes between
@@ -328,12 +336,12 @@ static int emulate_swpX(unsigned int address, unsigned int *data,
}
while (1) {
- unsigned long temp;
+ unsigned long temp, temp2;
if (type == TYPE_SWPB)
- __user_swpb_asm(*data, address, res, temp);
+ __user_swpb_asm(*data, address, res, temp, temp2);
else
- __user_swp_asm(*data, address, res, temp);
+ __user_swp_asm(*data, address, res, temp, temp2);
if (likely(res != -EAGAIN) || signal_pending(current))
break;
--
2.1.4
^ permalink raw reply related
* [PATCH/RFC 4/4] soc: renesas: Identify SoC and register with the SoC bus
From: Arnd Bergmann @ 2016-10-19 10:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMuHMdU=iTps+YfyeUyhPQkgSYHuG1hCLMFUTVOcPsHgbiPgSw@mail.gmail.com>
On Wednesday, October 19, 2016 10:02:57 AM CEST Geert Uytterhoeven wrote:
> On Mon, Oct 10, 2016 at 4:23 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Tuesday, October 4, 2016 11:09:27 AM CEST Geert Uytterhoeven wrote:
> >> +static const struct renesas_family fam_rza __initconst = {
> >> + .name = "RZ/A",
> >> +};
> >
> > I'm not sure about the relationship between this one and the others,
> > maybe it should be treated in the same way as emev2 and left out from
> > this driver?
>
> While RZ/A doesn't have a version registers (AFAIK), it shares several
> drivers with the other SoCs (SH/R-Mobile, R-Car).
> Hence I'd like to keep it, so we can match for it in these drivers when
> needed. It has e.g. a different variant of the serial port (SCIF), more
> closely to the one on SH2 rather than SH4.
I'd prefer seeing a separate soc driver for that one.
> >> +static const struct renesas_family fam_rmobile __initconst = {
> >> + .name = "R-Mobile",
> >> + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
> >> +};
> >> +
> >> +static const struct renesas_family fam_rcar_gen1 __initconst = {
> >> + .name = "R-Car Gen1",
> >> + .reg = 0xff000044, /* PRR (Product Register) */
> >> +};
> >> +
> >> +static const struct renesas_family fam_rcar_gen2 __initconst = {
> >> + .name = "R-Car Gen2",
> >> + .reg = 0xff000044, /* PRR (Product Register) */
> >> +};
> >> +
> >> +static const struct renesas_family fam_rcar_gen3 __initconst = {
> >> + .name = "R-Car Gen3",
> >> + .reg = 0xfff00044, /* PRR (Product Register) */
> >> +};
> >> +
> >> +static const struct renesas_family fam_rzg __initconst = {
> >> + .name = "RZ/G",
> >> + .reg = 0xff000044, /* PRR (Product Register) */
> >> +};
> >> +
> >> +static const struct renesas_family fam_shmobile __initconst = {
> >> + .name = "SH-Mobile",
> >> + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
> >> +};
> >
> > These seem to fall into two distinct categories, maybe there is a
> > better way to group them. What device contain the two kinds of
> > registers (PRR, CCCR)?
>
> Actually there are three (notice the extra "f" on R-Car Gen3 ;-)
I see. Hopefully this is just the same register block at a different
location though.
> Some SoCs have only CCCR, others have only PRR, some have both.
> On some SoCs one of them can be accessed from the RealTime CPU
> core (SH) only.
> On some SoCs the register is not documented, but present.
> If the PRR exists, it's a better choice, as it contains additional information
> in the high order bits (representing the presence of each big (CA15/CA57),
> little (CA7/CA53), and RT (CR7) CPU core). Currently we don't use that
> information, though.
>
> Grouping them in some other way means we would loose the family name,
> which is exposed through soc_dev_attr->family.
> The usefulness of family names is debatable though, as this is more an
> issue of marketing business.
How about having a table to look up the family name by the value
of the PRR or CCCR then?
> > Hardcoding the register address seems rather ugly here, so maybe
> > there is a way to have two separate probe methods based on the
> > surrounding register range, and then bind to that?
>
> There's no simple relation between CCCR/PRR and other register blocks.
> I prefer not to add these to DT, as that would add one more worm to the
> backwards compatibility can.
Hmm, I understand the concern about compatibility with existing DT files,
but I also really hate to see hardcoded register addresses.
Any reason against requiring the DT node for future chips though?
How about this:
The driver could report the hardcoded strings for the SoCs it already
knows about (you have the table anyway) and not report the revision
unless there is a regmap containing the CCCR or the PRR, in which
case you use that. Future SoCs will provide the PRR (I assume
CCCR is only used on the older ones) through a syscon regmap
that we can use to find out the exact revision as well.
The existing DT files can gain the syscon device so you can report
the revision on those machines as well, unless you use an old DTB.
> >> +static const struct of_device_id renesas_socs[] __initconst = {
> >> +#ifdef CONFIG_ARCH_EMEV2
> >> + { .compatible = "renesas,emev2", .data = &soc_emev2 },
> >> +#endif
> >> +#ifdef CONFIG_ARCH_R7S72100
> >> + { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
> >> +#endif
> >> +#ifdef CONFIG_ARCH_R8A73A4
> >
> > I think the #ifdefs here will result in warnings for unused symbols
> > when the Kconfig symbols are disabled.
>
> Originally I had __maybe_unused, but it didn't seem to be needed.
> Do you know which compiler needs it, so I can check?
Ah, I remember now: gcc doesn't warn for 'static const' variables
unless we pass -Wunused-const, which should be enabled with "make W=1",
and we might make that the default in the future (after fixing the
handful of drivers currently relying on this).
Why not just drop all the #ifdef here? There should be very little
overhead in size, especially if all the data is __initconst.
Arnd
^ permalink raw reply
* [PATCH v3 0/3] usb/phy: Add Amlogic Meson8b and GXBB USB support
From: Kishon Vijay Abraham I @ 2016-10-19 10:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAFBinCCoVOxyVYdNxeNyUhAK+T1+gBW0d1oDUgVpOZZHBjN9Wg@mail.gmail.com>
Hi,
On Friday 14 October 2016 01:57 AM, Martin Blumenstingl wrote:
> Hi Kishon,
>
> On Sat, Oct 1, 2016 at 2:18 PM, Martin Blumenstingl
> <martin.blumenstingl@googlemail.com> wrote:
>> Martin Blumenstingl (3):
>> Documentation: dt-bindings: update the meson-usb2-phy example
>> Documentation: dt-bindings: rename meson-usb2-phy to meson8b-usb2-phy
> these two already got an ACK by the devicetree maintainers
>
>> phy: meson: add USB2 PHY support for Meson8b and GXBB
> did you already have time to review the USB2 PHY driver from patch 3/3?
> please let me know if there's something we have to change, then I'll
> take care of it
>
> would you like to get all patches through the PHY tree or should Kevin
> take some of these?
while I have merged the patches to linux-phy -next, please update the
MAINTAINER for meson phy driver.
Thanks
Kishon
^ permalink raw reply
* [PATCH v4 2/8] scpi: Add alternative legacy structures, functions and macros
From: Sudeep Holla @ 2016-10-19 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d243c5f3-91b3-46ee-c456-49d3c9886742@arm.com>
On 19/10/16 11:37, Sudeep Holla wrote:
>
>
> On 19/10/16 11:28, Neil Armstrong wrote:
>> On 10/17/2016 01:16 PM, Sudeep Holla wrote:
>
> [...]
>
>>>
>>> and the above 2 can be moved out of the conditions, no ?
>>>
>>> if (scpi_info->is_legacy) {
>>> struct legacy_scpi_shared_mem *mem = ch->rx_payload;
>>> len = match->rx_len;
>>> } else {
>>> struct scpi_shared_mem *mem = ch->rx_payload;
>>> len = min(match->rx_len, CMD_SIZE(cmd));
>>> }
>>> match->status = le32_to_cpu(mem->status);
>>> memcpy_fromio(match->rx_buf, mem->payload, len);
>>>
>>> should work.
>>
>> Well, we will have "error: ?mem? undeclared (first use in this
>> function)" since mem is not declared outside the if/else.
>>
>> I don't see good solutions even with an union.
>
> Right, I missed to see that. You can leave it as you had before then.
>
>
> [...]
>>>>>> if (t->rx_buf) {
>>>>>> if (!(++ch->token))
>>>>>> ++ch->token;
>>>>>> ADD_SCPI_TOKEN(t->cmd, ch->token);
>>>>>> + if (scpi_info->is_legacy)
>>>>>> + t->slot = t->cmd;
>>>>>
>>>>> I thought passing token was not an issue from your previous response,
>>>>> but you are overriding it here, why ?
>>>>
>>>> Indeed, I can leave it, but it's useless since it won't serve to
>>>> distinguish multiple similar commands.
>>>>
>>>
>>> OK, I don't see any point in such micro optimization, so please
>>> retain it.
>>>
>>
>> I misread my code, I leaved the token passing, but I copy back the
>> cmd to the slot which is used by the MHU.
>> If I remove the "t->slot = t->cmd;", the token won't be passed to the
>> FW.
>>
>
> Right, sorry I think I misled you :)
>
On the other hand, if we are unable to use that in the driver as you
just have FIFO in the list for this legacy mode, I think we can drop it
completely. I know I had argued otherwise before, but that was before I
realized that we need to keep FIFO in the list ;). Let me know if you
are OK to drop it.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH v4 2/8] scpi: Add alternative legacy structures, functions and macros
From: Sudeep Holla @ 2016-10-19 10:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <24e6ef19-b88d-a5b8-f514-d39a7b5725e8@baylibre.com>
On 19/10/16 11:28, Neil Armstrong wrote:
> On 10/17/2016 01:16 PM, Sudeep Holla wrote:
[...]
>>
>> and the above 2 can be moved out of the conditions, no ?
>>
>> if (scpi_info->is_legacy) {
>> struct legacy_scpi_shared_mem *mem = ch->rx_payload;
>> len = match->rx_len;
>> } else {
>> struct scpi_shared_mem *mem = ch->rx_payload;
>> len = min(match->rx_len, CMD_SIZE(cmd));
>> }
>> match->status = le32_to_cpu(mem->status);
>> memcpy_fromio(match->rx_buf, mem->payload, len);
>>
>> should work.
>
> Well, we will have "error: ?mem? undeclared (first use in this
> function)" since mem is not declared outside the if/else.
>
> I don't see good solutions even with an union.
Right, I missed to see that. You can leave it as you had before then.
[...]
>>>>> if (t->rx_buf) {
>>>>> if (!(++ch->token))
>>>>> ++ch->token;
>>>>> ADD_SCPI_TOKEN(t->cmd, ch->token);
>>>>> + if (scpi_info->is_legacy)
>>>>> + t->slot = t->cmd;
>>>>
>>>> I thought passing token was not an issue from your previous response,
>>>> but you are overriding it here, why ?
>>>
>>> Indeed, I can leave it, but it's useless since it won't serve to
>>> distinguish multiple similar commands.
>>>
>>
>> OK, I don't see any point in such micro optimization, so please retain it.
>>
>
> I misread my code, I leaved the token passing, but I copy back the
> cmd to the slot which is used by the MHU.
> If I remove the "t->slot = t->cmd;", the token won't be passed to the
> FW.
>
Right, sorry I think I misled you :)
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH 0/4] soc: renesas: Identify SoC and register with the SoC bus
From: Arnd Bergmann @ 2016-10-19 10:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMuHMdXb=t39+qt6te59G827c_Be-_kmuS-D1B-D5zD1CsuOAw@mail.gmail.com>
On Wednesday, October 19, 2016 10:10:38 AM CEST Geert Uytterhoeven wrote:
> Hi Arnd,
>
> On Mon, Oct 10, 2016 at 4:28 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Tuesday, October 4, 2016 11:09:23 AM CEST Geert Uytterhoeven wrote:
> >> Some Renesas SoCs may exist in different revisions, providing slightly
> >> different functionalities (e.g. R-Car H3 ES1.x and ES2.0). This needs to
> >> be catered for by drivers and/or platform code. The recently proposed
> >> soc_device_match() API seems like a good fit to handle this.
> >>
> >> This patch series implements the core infrastructure to provide SoC and
> >> revision information through the SoC bus for Renesas ARM SoCs. It
> >> consists of 4 patches:
> >> - Patch 1 avoids a crash when SoC revision information is needed and
> >> provided early,
> >> - Patch 2 (from Arnd) introduces the soc_device_match() API.
> >> I don't know if, when, and through which channel this patch is
> >> planned to go upstream,
> >> - Patch 3 fixes a bug in soc_device_match(), causing a crash when
> >> trying to match on an SoC attribute that is not provided (seen on
> >> EMEV2, RZ/A, and R-Car M1A, which lack revision information),
> >> - Patch 4 identifies Renesas SoCs and registers them with the SoC bus.
> >>
> >> Tested on (family, machine, soc_id, optional revision):
> >>
> >> Emma Mobile EV2, EMEV2 KZM9D Board, emev2
> >> RZ/A, Genmai, r7s72100
> >> R-Mobile, APE6EVM, r8a73a4, ES1.0
> >> R-Mobile, armadillo 800 eva, r8a7740, ES2.0
> >> R-Car Gen1, bockw, r8a7778
> >> R-Car Gen1, marzen, r8a7779, ES1.0
> >> R-Car Gen2, Lager, r8a7790, ES1.0
> >> R-Car Gen2, Koelsch, r8a7791, ES1.0
> >> R-Car Gen2, Gose, r8a7793, ES1.0
> >> R-Car Gen2, Alt, r8a7794, ES1.0
> >> R-Car Gen3, Renesas Salvator-X board based on r8a7795, r8a7795, ES1.0
> >> R-Car Gen3, Renesas Salvator-X board based on r8a7796, r8a7796, ES1.0
> >> SH-Mobile, KZM-A9-GT, sh73a0, ES2.0
> >
> > As mentioned in the comment for the driver patch, I think this makes
> > a lot of sense for the machines that have a revision register, in
> > particular when the interpretation of that register is always done
> > the same way, but I'm a bit skeptical about doing it in the same driver
> > for machines that don't have the register.
> >
> > Matching by a device rather than the SoC platform also has the advantage
> > that there is no need to maintain a list of compatible numbers in the
> > driver.
>
> Currently we (usually) use:
> - SoC-specific compatible values, to handle known differences within the
> same family now, and handle future unknown differences,
> - Family-specific compatible values, which we define ourselves.
>
> Usually drivers match on the latter.
>
> Every time a new SoC is introduced, we have to update lots of DT binding
> docs, to add the new SoC-specific compatible values.
>
> Two-phase matching (driver code matches against "renesas,<foo>",
> driver matches against SoC using soc_device_match()) would allow to
> remove the burden of updating DT documentation all the time.
> The drivers would need updates, though.
> Another advantage would be that we can reuse .dtsi snippets for SoCs in
> the same family, which we currently can't easily do due to the SoC-specific
> compatible values.
Interesting idea, but unrelated to my comment above, which was about
the soc driver in particular, rather the drivers using it.
Arnd
^ permalink raw reply
* [PATCH] iommu: convert DT component matching to component_match_add_release()
From: Russell King @ 2016-10-19 10:30 UTC (permalink / raw)
To: linux-arm-kernel
Convert DT component matching to use component_match_add_release().
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/iommu/mtk_iommu.c | 8 +++++---
drivers/iommu/mtk_iommu.h | 5 +++++
drivers/iommu/mtk_iommu_v1.c | 8 +++++---
3 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index b12c12d74c33..41604796fca3 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -583,17 +583,19 @@ static int mtk_iommu_probe(struct platform_device *pdev)
continue;
plarbdev = of_find_device_by_node(larbnode);
- of_node_put(larbnode);
if (!plarbdev) {
plarbdev = of_platform_device_create(
larbnode, NULL,
platform_bus_type.dev_root);
- if (!plarbdev)
+ if (!plarbdev) {
+ of_node_put(larbnode);
return -EPROBE_DEFER;
+ }
}
data->smi_imu.larb_imu[i].dev = &plarbdev->dev;
- component_match_add(dev, &match, compare_of, larbnode);
+ component_match_add_release(dev, &match, release_of,
+ compare_of, larbnode);
}
platform_set_drvdata(pdev, data);
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
index 3dab13b4a211..44ca38095c6a 100644
--- a/drivers/iommu/mtk_iommu.h
+++ b/drivers/iommu/mtk_iommu.h
@@ -60,6 +60,11 @@ static inline int compare_of(struct device *dev, void *data)
return dev->of_node == data;
}
+static inline void release_of(struct device *dev, void *data)
+{
+ of_node_put(data);
+}
+
static inline int mtk_iommu_bind(struct device *dev)
{
struct mtk_iommu_data *data = dev_get_drvdata(dev);
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index b8aeb0768483..92341ef33354 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -624,17 +624,19 @@ static int mtk_iommu_probe(struct platform_device *pdev)
continue;
plarbdev = of_find_device_by_node(larb_spec.np);
- of_node_put(larb_spec.np);
if (!plarbdev) {
plarbdev = of_platform_device_create(
larb_spec.np, NULL,
platform_bus_type.dev_root);
- if (!plarbdev)
+ if (!plarbdev) {
+ of_node_put(larb_spec.np);
return -EPROBE_DEFER;
+ }
}
data->smi_imu.larb_imu[larb_nr].dev = &plarbdev->dev;
- component_match_add(dev, &match, compare_of, larb_spec.np);
+ component_match_add_release(dev, &match, release_of,
+ compare_of, larb_spec.np);
larb_nr++;
}
--
2.1.0
^ permalink raw reply related
* [PATCH v4 2/8] scpi: Add alternative legacy structures, functions and macros
From: Neil Armstrong @ 2016-10-19 10:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e3f774ee-5268-3668-e7f8-0ae3bbceba6c@arm.com>
On 10/17/2016 01:16 PM, Sudeep Holla wrote:
>
>
> On 17/10/16 09:25, Neil Armstrong wrote:
>> On 10/10/2016 04:36 PM, Sudeep Holla wrote:
>>> Hi Neil,
>>>
>>> Sorry, I could not reply to your response on v3. Anyways I will review v4.
>>>
>>> On 05/10/16 08:33, Neil Armstrong wrote:
>>>> This patch adds support for the Legacy SCPI protocol in early JUNO versions and
>>>> shipped Amlogic ARMv8 based SoCs. Some Rockchip SoC are also known to use this
>>>> version of protocol with extended vendor commands
>>>> .
>>>> In order to support the legacy SCPI protocol variant, add back the structures
>>>> and macros that varies against the final specification.
>>>> Then add indirection table for legacy commands.
>>>> Finally Add bitmap field for channel selection since the Legacy protocol mandates to
>>>> send a selected subset of the commands on the high priority channel instead of the
>>>> low priority channel.
>>>>
>>>> The message sending path differs from the final SCPI procotocol because the
>>>> Amlogic SCP firmware always reply 1 instead of a special value containing the command
>>>> byte and replied rx data length.
>>>> For this reason commands queuing cannot be used and we assume the reply command is
>>>> the head of the rx_pending list since we ensure sequential command sending with a
>>>> separate dedicated mutex.
>>>>
>>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>>> ---
>>>> drivers/firmware/arm_scpi.c | 221 +++++++++++++++++++++++++++++++++++++++-----
>>>> 1 file changed, 199 insertions(+), 22 deletions(-)
>>>>
>>>> diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
>>>> index 498afa0..6244eb1 100644
>>>> --- a/drivers/firmware/arm_scpi.c
>>>> +++ b/drivers/firmware/arm_scpi.c
>>>
>>> [...]
>>>
>>>> @@ -307,21 +398,46 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
>>>> return;
>>>> }
>>>>
>>>> - list_for_each_entry(t, &ch->rx_pending, node)
>>>> - if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
>>>> - list_del(&t->node);
>>>> - match = t;
>>>> - break;
>>>> - }
>>>> + /* Command type is not replied by the SCP Firmware in legacy Mode
>>>> + * We should consider that command is the head of pending RX commands
>>>> + * if the list is not empty. In TX only mode, the list would be empty.
>>>> + */
>>>> + if (scpi_info->is_legacy) {
>>>> + match = list_first_entry(&ch->rx_pending, struct scpi_xfer,
>>>> + node);
>>>> + list_del(&match->node);
>>>> + } else {
>>>> + list_for_each_entry(t, &ch->rx_pending, node)
>>>> + if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
>>>> + list_del(&t->node);
>>>> + match = t;
>>>> + break;
>>>> + }
>>>> + }
>>>> /* check if wait_for_completion is in progress or timed-out */
>>>> if (match && !completion_done(&match->done)) {
>>>> - struct scpi_shared_mem *mem = ch->rx_payload;
>>>> - unsigned int len = min(match->rx_len, CMD_SIZE(cmd));
>>>> + unsigned int len;
>>>> +
>>>> + if (scpi_info->is_legacy) {
>>>> + struct legacy_scpi_shared_mem *mem = ch->rx_payload;
>>>> +
>>>> + /* RX Length is not replied by the lagcy Firmware */
>
> Typo above legacy
>
>>>> + len = match->rx_len;
>>>> +
>>>> + match->status = le32_to_cpu(mem->status);
>>>> + memcpy_fromio(match->rx_buf, mem->payload, len);
>>>
>>> The above 2 seems common to both, no ?
>>
>> No, the shared_mem structure differs.
>>
>
> Yes I see that, I was just referring the last 2 statements.
>
>>>
>>>> + } else {
>>>> + struct scpi_shared_mem *mem = ch->rx_payload;
>>>> +
>>>> + len = min(match->rx_len, CMD_SIZE(cmd));
>>>> +
>>>> + match->status = le32_to_cpu(mem->status);
>>>> + memcpy_fromio(match->rx_buf, mem->payload, len);
>
> and the above 2 can be moved out of the conditions, no ?
>
> if (scpi_info->is_legacy) {
> struct legacy_scpi_shared_mem *mem = ch->rx_payload;
> len = match->rx_len;
> } else {
> struct scpi_shared_mem *mem = ch->rx_payload;
> len = min(match->rx_len, CMD_SIZE(cmd));
> }
> match->status = le32_to_cpu(mem->status);
> memcpy_fromio(match->rx_buf, mem->payload, len);
>
> should work.
Well, we will have "error: ?mem? undeclared (first use in this function)" since mem is not declared outside the if/else.
I don't see good solutions even with an union.
>
> [...]
>
>>>
>>>> + else
>>>> + cmd = le32_to_cpu(mem->command);
>>>>
>>>> scpi_process_cmd(ch, cmd);
>>>> }
>>>> @@ -343,17 +464,26 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
>>>> struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
>>>> struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
>>>>
>>>> - if (t->tx_buf)
>>>> - memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
>>>> + if (t->tx_buf) {
>>>> + if (scpi_info->is_legacy)
>>>> + memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len);
>>>> + else
>>>> + memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
>>>> + }
>>>> +
>>>> if (t->rx_buf) {
>>>> if (!(++ch->token))
>>>> ++ch->token;
>>>> ADD_SCPI_TOKEN(t->cmd, ch->token);
>>>> + if (scpi_info->is_legacy)
>>>> + t->slot = t->cmd;
>>>
>>> I thought passing token was not an issue from your previous response,
>>> but you are overriding it here, why ?
>>
>> Indeed, I can leave it, but it's useless since it won't serve to
>> distinguish multiple similar commands.
>>
>
> OK, I don't see any point in such micro optimization, so please retain it.
>
I misread my code, I leaved the token passing, but I copy back the cmd to the slot which is used by the MHU.
If I remove the "t->slot = t->cmd;", the token won't be passed to the FW.
> [...]
>
>>>> + /* Since we cannot distinguish the original command in the
>>>> + * MHU reply stat value from a Legacy SCP firmware, ensure
>>>> + * sequential command sending to the firmware.
>>>> + */
>>>
>>> OK this comment now questions the existence of this extra lock.
>>> The mailbox will always send the commands in the sequential order.
>>> It's only firmware that can re-order the response. Since that can't
>>> happen in you case, I really don't see the need for this.
>>>
>>> Please explain the race you would see without this locking. Yes I
>>> understand that only one command is supposed to be sent to firmware at a
>>> time. Suppose you allow more callers here, all will wait on the
>>> completion flags and the first in the list gets unblocked right ?
>>> I am just trying to understand if there's real need for this extra
>>> lock when we already have that from the list.
>>
>> In my current tests I have huge kernel hang when having multiple callers,
>> I must find out where this issue comes from...
>
> Yes IMO, you should understand the root cause of this issue. There may
> be issue with the existing driver itself. But just adding a lock just to
> avoid the hang without understanding it is wrong.
>
>> In any case, we have an issue about the command sequencing. If we
>> push a tx-only command and then right after a tx-rx command, the
>> mailbox callback from the first command won't be able to distinguish
>> which command is handled !
>
> Hmm, how exactly ? I won't expect scpi_handle_remote_msg to becalled in
> that case.
>
>> In this case, the rx_pending list will not be empty, some garbage
>> will be returned to the second command handler and the real data from
>> the second command handling will be lost thinking it's a tx-only
>> command.
>>
>
> Yes as I said why is scpi_handle_remote_msg called for tx only command.
> And more over we don't have any tx only command in the driver, I am
> still unable to understand the issue you are facing. Are you sure you
> have tx-only command in the failure/hang case ?
>
>>
>> We have two choices here : - Also push the tx-only commands to the
>> rx_pending list, and also wait for their completion
>
> See above, I need to know details on this tx-only command. In fact, they
> may not be tx-only as SCP is sending some response back, may just status.
>
>> - Add an extra lock
>>
>
> Not this for sure.
>
>> What is your preferred scheme ?
>>
>
> Option 1 if it legitimate case. I mean we may be misunderstanding the
> definition of tx-only command.
>
>
>>>> + if (scpi_info->is_legacy)
>>>> + mutex_lock(&scpi_chan->legacy_lock);
>>>> +
>>>> ret = mbox_send_message(scpi_chan->chan, msg);
>>>> if (ret < 0 || !rx_buf)
>>>> goto out;
>>>> @@ -421,9 +567,13 @@ static int scpi_send_message(unsigned int offset, void *tx_buf,
>>>> /* first status word */
>>>> ret = msg->status;
>>>> out:
>>>> - if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
>>>> + if (ret < 0 && rx_buf)
>>>> + /* remove entry from the list if timed-out */
>>>> scpi_process_cmd(scpi_chan, msg->cmd);
>>>>
>>>> + if (scpi_info->is_legacy)
>>>> + mutex_unlock(&scpi_chan->legacy_lock);
>>>> +
>>>> put_scpi_xfer(msg, scpi_chan);
>>>> /* SCPI error codes > 0, translate them to Linux scale*/
>>>> return ret > 0 ? scpi_to_linux_errno(ret) : ret;
>>>
>
> [...]
>
>>
>> I will fix the issues, but I need your advice for the locking scheme. I really want this
>> to be merged and be able to go forward !
>>
>
> Yes I agree and I have no major concern with the series now except the
> locking.
>
^ permalink raw reply
* [PATCH] drm: convert DT component matching to component_match_add_release()
From: Russell King @ 2016-10-19 10:28 UTC (permalink / raw)
To: linux-arm-kernel
Convert DT component matching to use component_match_add_release().
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
Can we please get this patch from May merged into the drm-misc or
whatever trees so that we don't end up with conflicts? I've no idea
who looks after drm-misc, as they have _still_ failed to add
themselves to MAINTAINERS.
drivers/gpu/drm/arm/hdlcd_drv.c | 3 ++-
drivers/gpu/drm/arm/malidp_drv.c | 4 +++-
drivers/gpu/drm/armada/armada_drv.c | 2 +-
drivers/gpu/drm/drm_of.c | 28 +++++++++++++++++++++++--
drivers/gpu/drm/etnaviv/etnaviv_drv.c | 5 +++--
drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 7 ++++---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 4 +++-
drivers/gpu/drm/msm/msm_drv.c | 12 ++++++-----
drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 6 ++++--
drivers/gpu/drm/sti/sti_drv.c | 5 +++--
drivers/gpu/drm/sun4i/sun4i_drv.c | 3 ++-
drivers/gpu/drm/tilcdc/tilcdc_external.c | 4 +++-
include/drm/drm_of.h | 12 +++++++++++
13 files changed, 73 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index fb6a418ce6be..6477d1a65266 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -453,7 +453,8 @@ static int hdlcd_probe(struct platform_device *pdev)
return -EAGAIN;
}
- component_match_add(&pdev->dev, &match, compare_dev, port);
+ drm_of_component_match_add(&pdev->dev, &match, compare_dev, port);
+ of_node_put(port);
return component_master_add_with_match(&pdev->dev, &hdlcd_master_ops,
match);
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 9280358b8f15..9f4739452a25 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -493,7 +493,9 @@ static int malidp_platform_probe(struct platform_device *pdev)
return -EAGAIN;
}
- component_match_add(&pdev->dev, &match, malidp_compare_dev, port);
+ drm_of_component_match_add(&pdev->dev, &match, malidp_compare_dev,
+ port);
+ of_node_put(port);
return component_master_add_with_match(&pdev->dev, &malidp_master_ops,
match);
}
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 1e0e68f608e4..94e46da9a758 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -254,7 +254,7 @@ static void armada_add_endpoints(struct device *dev,
continue;
}
- component_match_add(dev, match, compare_of, remote);
+ drm_of_component_match_add(dev, match, compare_of, remote);
of_node_put(remote);
}
}
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index bc98bb94264d..47848ed8ca48 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -6,6 +6,11 @@
#include <drm/drm_crtc.h>
#include <drm/drm_of.h>
+static void drm_release_of(struct device *dev, void *data)
+{
+ of_node_put(data);
+}
+
/**
* drm_crtc_port_mask - find the mask of a registered CRTC by port OF node
* @dev: DRM device
@@ -64,6 +69,24 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
EXPORT_SYMBOL(drm_of_find_possible_crtcs);
/**
+ * drm_of_component_match_add - Add a component helper OF node match rule
+ * @master: master device
+ * @matchptr: component match pointer
+ * @compare: compare function used for matching component
+ * @node: of_node
+ */
+void drm_of_component_match_add(struct device *master,
+ struct component_match **matchptr,
+ int (*compare)(struct device *, void *),
+ struct device_node *node)
+{
+ of_node_get(node);
+ component_match_add_release(master, matchptr, drm_release_of,
+ compare, node);
+}
+EXPORT_SYMBOL_GPL(drm_of_component_match_add);
+
+/**
* drm_of_component_probe - Generic probe function for a component based master
* @dev: master device containing the OF node
* @compare_of: compare function used for matching components
@@ -101,7 +124,7 @@ int drm_of_component_probe(struct device *dev,
continue;
}
- component_match_add(dev, &match, compare_of, port);
+ drm_of_component_match_add(dev, &match, compare_of, port);
of_node_put(port);
}
@@ -140,7 +163,8 @@ int drm_of_component_probe(struct device *dev,
continue;
}
- component_match_add(dev, &match, compare_of, remote);
+ drm_of_component_match_add(dev, &match, compare_of,
+ remote);
of_node_put(remote);
}
of_node_put(port);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index aa687669e22b..0dee6acbd880 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -16,6 +16,7 @@
#include <linux/component.h>
#include <linux/of_platform.h>
+#include <drm/drm_of.h>
#include "etnaviv_drv.h"
#include "etnaviv_gpu.h"
@@ -629,8 +630,8 @@ static int etnaviv_pdev_probe(struct platform_device *pdev)
if (!core_node)
break;
- component_match_add(&pdev->dev, &match, compare_of,
- core_node);
+ drm_of_component_match_add(&pdev->dev, &match,
+ compare_of, core_node);
of_node_put(core_node);
}
} else if (dev->platform_data) {
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
index 90377a609c98..e88fde18c946 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -24,6 +24,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
#include "kirin_drm_drv.h"
@@ -260,14 +261,13 @@ static struct device_node *kirin_get_remote_node(struct device_node *np)
DRM_ERROR("no valid endpoint node\n");
return ERR_PTR(-ENODEV);
}
- of_node_put(endpoint);
remote = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
if (!remote) {
DRM_ERROR("no valid remote node\n");
return ERR_PTR(-ENODEV);
}
- of_node_put(remote);
if (!of_device_is_available(remote)) {
DRM_ERROR("not available for remote node\n");
@@ -294,7 +294,8 @@ static int kirin_drm_platform_probe(struct platform_device *pdev)
if (IS_ERR(remote))
return PTR_ERR(remote);
- component_match_add(dev, &match, compare_of, remote);
+ drm_of_component_match_add(dev, &match, compare_of, remote);
+ of_node_put(remote);
return component_master_add_with_match(dev, &kirin_drm_ops, match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index cf83f6507ec8..9c5430fb82a2 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -18,6 +18,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
#include <linux/component.h>
#include <linux/iommu.h>
#include <linux/of_address.h>
@@ -415,7 +416,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
comp_type == MTK_DPI) {
dev_info(dev, "Adding component match for %s\n",
node->full_name);
- component_match_add(dev, &match, compare_of, node);
+ drm_of_component_match_add(dev, &match, compare_of,
+ node);
} else {
struct mtk_ddp_comp *comp;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index fb5c0b0a7594..84d38eaea585 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -15,6 +15,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <drm/drm_of.h>
+
#include "msm_drv.h"
#include "msm_debugfs.h"
#include "msm_fence.h"
@@ -919,8 +921,8 @@ static int add_components_mdp(struct device *mdp_dev,
continue;
}
- component_match_add(master_dev, matchptr, compare_of, intf);
-
+ drm_of_component_match_add(master_dev, matchptr, compare_of,
+ intf);
of_node_put(intf);
of_node_put(ep_node);
}
@@ -962,8 +964,8 @@ static int add_display_components(struct device *dev,
put_device(mdp_dev);
/* add the MDP component itself */
- component_match_add(dev, matchptr, compare_of,
- mdp_dev->of_node);
+ drm_of_component_match_add(dev, matchptr, compare_of,
+ mdp_dev->of_node);
} else {
/* MDP4 */
mdp_dev = dev;
@@ -996,7 +998,7 @@ static int add_gpu_components(struct device *dev,
if (!np)
return 0;
- component_match_add(dev, matchptr, compare_of, np);
+ drm_of_component_match_add(dev, matchptr, compare_of, np);
of_node_put(np);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 8c8cbe837e61..6fe161192bb4 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -20,6 +20,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
@@ -388,7 +389,7 @@ static void rockchip_add_endpoints(struct device *dev,
continue;
}
- component_match_add(dev, match, compare_of, remote);
+ drm_of_component_match_add(dev, match, compare_of, remote);
of_node_put(remote);
}
}
@@ -437,7 +438,8 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev)
}
of_node_put(iommu);
- component_match_add(dev, &match, compare_of, port->parent);
+ drm_of_component_match_add(dev, &match, compare_of,
+ port->parent);
of_node_put(port);
}
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 2784919a7366..5e819876e642 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -17,6 +17,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_of.h>
#include "sti_crtc.h"
#include "sti_drv.h"
@@ -423,8 +424,8 @@ static int sti_platform_probe(struct platform_device *pdev)
child_np = of_get_next_available_child(node, NULL);
while (child_np) {
- component_match_add(dev, &match, compare_of, child_np);
- of_node_put(child_np);
+ drm_of_component_match_add(dev, &match, compare_of,
+ child_np);
child_np = of_get_next_available_child(node, child_np);
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 0da9862ad8ed..b3c4ad605e81 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -18,6 +18,7 @@
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_helper.h>
+#include <drm/drm_of.h>
#include "sun4i_crtc.h"
#include "sun4i_drv.h"
@@ -239,7 +240,7 @@ static int sun4i_drv_add_endpoints(struct device *dev,
/* Add current component */
DRM_DEBUG_DRIVER("Adding component %s\n",
of_node_full_name(node));
- component_match_add(dev, match, compare_of, node);
+ drm_of_component_match_add(dev, match, compare_of, node);
count++;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index 68e895021005..06a4c584f3cb 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -10,6 +10,7 @@
#include <linux/component.h>
#include <linux/of_graph.h>
+#include <drm/drm_of.h>
#include "tilcdc_drv.h"
#include "tilcdc_external.h"
@@ -160,7 +161,8 @@ int tilcdc_get_external_components(struct device *dev,
dev_dbg(dev, "Subdevice node '%s' found\n", node->name);
if (match)
- component_match_add(dev, match, dev_match_of, node);
+ drm_of_component_match_add(dev, match, dev_match_of,
+ node);
of_node_put(node);
count++;
}
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
index 3fd87b386ed7..d6b4c5587bbe 100644
--- a/include/drm/drm_of.h
+++ b/include/drm/drm_of.h
@@ -4,6 +4,7 @@
#include <linux/of_graph.h>
struct component_master_ops;
+struct component_match;
struct device;
struct drm_device;
struct drm_encoder;
@@ -12,6 +13,10 @@ struct device_node;
#ifdef CONFIG_OF
extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
struct device_node *port);
+extern void drm_of_component_match_add(struct device *master,
+ struct component_match **matchptr,
+ int (*compare)(struct device *, void *),
+ struct device_node *node);
extern int drm_of_component_probe(struct device *dev,
int (*compare_of)(struct device *, void *),
const struct component_master_ops *m_ops);
@@ -25,6 +30,13 @@ static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
return 0;
}
+static void drm_of_component_match_add(struct device *master,
+ struct component_match **matchptr,
+ int (*compare)(struct device *, void *),
+ struct device_node *node)
+{
+}
+
static inline int
drm_of_component_probe(struct device *dev,
int (*compare_of)(struct device *, void *),
--
2.1.0
^ permalink raw reply related
* [PATCH] arm64: Cortex-A53 errata workaround: check for kernel addresses
From: Andre Przywara @ 2016-10-19 10:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161018130047.GC15639@leverpostej>
Hi Mark,
On 18/10/16 14:00, Mark Rutland wrote:
> On Tue, Oct 18, 2016 at 12:16:27PM +0100, Andre Przywara wrote:
>> Commit 7dd01aef0557 ("arm64: trap userspace "dc cvau" cache operation on
>> errata-affected core") adds code to execute cache maintenance instructions
>> in the kernel on behalf of userland on CPUs with certain ARM CPU errata.
>> It turns out that the address hasn't been checked to be a valid user
>> space address, allowing userland to clean cache lines in kernel space.
>> Fix this by introducing an access_ok() check before executing the
>> instructions on behalf of userland, taking care of tagged pointers on
>> the way.
>
> It would be worth calling out why we need access_ok_tagged here (i.e.
> since this is not a syscall, the tag bits may validly be set, and we
> must mask them out to check the "real" address).
Agreed.
>
>> Reported-by: Kristina Martsenko <kristina.martsenko@arm.com>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> Cc: <stable@vger.kernel.org> # 4.8.x
>
> It would be good to have an explicit:
>
> Fixes: 7dd01aef0557 ("arm64: trap userspace "dc cvau" cache operation on errata-affected core")
>
>> ---
>> arch/arm64/include/asm/uaccess.h | 4 ++++
>> arch/arm64/kernel/traps.c | 32 ++++++++++++++++++++++++++++----
>> 2 files changed, 32 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
>> index bcaf6fb..f842b47 100644
>> --- a/arch/arm64/include/asm/uaccess.h
>> +++ b/arch/arm64/include/asm/uaccess.h
>> @@ -21,6 +21,7 @@
>> /*
>> * User space memory access functions
>> */
>> +#include <linux/bitops.h>
>> #include <linux/kasan-checks.h>
>> #include <linux/string.h>
>> #include <linux/thread_info.h>
>> @@ -103,6 +104,9 @@ static inline void set_fs(mm_segment_t fs)
>> })
>>
>> #define access_ok(type, addr, size) __range_ok(addr, size)
>> +#define access_ok_tagged(type, addr, size) access_ok(type, \
>> + sign_extend64(addr, 55), \
>> + size)
>> #define user_addr_max get_fs
>>
>> #define _ASM_EXTABLE(from, to) \
>> diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
>> index 5ff020f..04ea0d7 100644
>> --- a/arch/arm64/kernel/traps.c
>> +++ b/arch/arm64/kernel/traps.c
>> @@ -447,6 +447,30 @@ void cpu_enable_cache_maint_trap(void *__unused)
>> : "=r" (res) \
>> : "r" (address), "i" (-EFAULT) )
>>
>> +enum {USER_CACHE_MAINT_DC_CIVAC, USER_CACHE_MAINT_IC_IVAU};
>> +
>> +static int do_user_cache_maint(int ins_type, unsigned long address)
>> +{
>> + int ret;
>> + unsigned long cl_size = cache_line_size();
>> +
>> + if (!access_ok_tagged(VERIFY_READ,
>> + round_down(address, cl_size),
>> + cl_size))
>> + return -EFAULT;
>
> We're only checking the D$ line size here; the I$ is not reported by
> cache_line_size().
>
> We may as well use PAGE_SIZE here, given cache lines have to be
> naturally aligned and permissions are at page granularity. There's no
> functional difference, but the value can't change under our feet, and
> the compiler may be able to better optimize by folding the contant in.
Yeah, I was thinking about that as well, but found cache_line_size() to
be more readable. I will replace this with PAGE_SIZE and a comment.
>> +
>> + switch (ins_type) {
>> + case USER_CACHE_MAINT_DC_CIVAC:
>> + __user_cache_maint("dc civac", address, ret);
>> + break;
>> + case USER_CACHE_MAINT_IC_IVAU:
>> + __user_cache_maint("ic ivau", address, ret);
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>
> We could make this function a macro (passing in the instruction
> explicitly), and avoid the enum and switch.
I am not a big fan of putting too much stuff into a macro. After all the
kernel is written in C, not CPP ;-)
But now that the access check can use PAGE_SIZE, it should be much
simpler, so I will give it a try.
>
> Other than that, this looks good to me.
Thanks for looking at this!
Cheers,
Andre.
>
> Thanks,
> Mark.
>
>> +
>> static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
>> {
>> unsigned long address;
>> @@ -458,16 +482,16 @@ static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
>>
>> switch (crm) {
>> case ESR_ELx_SYS64_ISS_CRM_DC_CVAU: /* DC CVAU, gets promoted */
>> - __user_cache_maint("dc civac", address, ret);
>> + ret = do_user_cache_maint(USER_CACHE_MAINT_DC_CIVAC, address);
>> break;
>> case ESR_ELx_SYS64_ISS_CRM_DC_CVAC: /* DC CVAC, gets promoted */
>> - __user_cache_maint("dc civac", address, ret);
>> + ret = do_user_cache_maint(USER_CACHE_MAINT_DC_CIVAC, address);
>> break;
>> case ESR_ELx_SYS64_ISS_CRM_DC_CIVAC: /* DC CIVAC */
>> - __user_cache_maint("dc civac", address, ret);
>> + ret = do_user_cache_maint(USER_CACHE_MAINT_DC_CIVAC, address);
>> break;
>> case ESR_ELx_SYS64_ISS_CRM_IC_IVAU: /* IC IVAU */
>> - __user_cache_maint("ic ivau", address, ret);
>> + ret = do_user_cache_maint(USER_CACHE_MAINT_IC_IVAU, address);
>> break;
>> default:
>> force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
>> --
>> 2.9.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 0/5] Switch to the DT cpufreq policy on the Integrator
From: Arnd Bergmann @ 2016-10-19 10:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871154-32243-1-git-send-email-linus.walleij@linaro.org>
On Wednesday, October 19, 2016 11:59:09 AM CEST Linus Walleij wrote:
>
> If people are happy with this approach and approve of the patches
> I'd like an ACK from the cpufreq people and then merge the whole set
> through ARM SoC.
>
I don't see any hard dependency here, so I'd suggest to merge the
two cpufreq patches through the subsystem tree, and the ARM patches
through arm-soc.
The patches look fine.
Removing the custom driver of course means that we break machines
with old .dtb files, so we could consider leaving the driver in
place, but probably there is no need for integrator.
Arnd
^ permalink raw reply
* [PATCH] extcon: qcom-spmi-misc: Sync the extcon state on interrupt
From: Chanwoo Choi @ 2016-10-19 10:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161018001602.18617-1-stephen.boyd@linaro.org>
Hi Stephen,
On 2016? 10? 18? 09:16, Stephen Boyd wrote:
> The driver was changed after submission to use the new style APIs
> like extcon_set_state(). Unfortunately, that only sets the state,
> and doesn't notify any consumers that the cable state has
> changed. Use extcon_set_state_sync() here instead so that we
> notify cable consumers of the state change. This fixes USB
> host-device role switching on the db8074 platform.
>
> Fixes: 38085c987f52 ("extcon: Add support for qcom SPMI PMIC USB id detection hardware")
> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
> ---
> drivers/extcon/extcon-qcom-spmi-misc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
> index ca957a5f4291..b8cde096a808 100644
> --- a/drivers/extcon/extcon-qcom-spmi-misc.c
> +++ b/drivers/extcon/extcon-qcom-spmi-misc.c
> @@ -51,7 +51,7 @@ static void qcom_usb_extcon_detect_cable(struct work_struct *work)
> if (ret)
> return;
>
> - extcon_set_state(info->edev, EXTCON_USB_HOST, !id);
> + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, !id);
> }
>
> static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id)
>
Applied it.
Best Regards,
Chanwoo Choi
^ permalink raw reply
* [PATCH 9/9] ARM: dts: amlogic: enable gpio interrupt controller on meson8
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/boot/dts/meson8.dtsi | 11 +++++++++++
arch/arm/boot/dts/meson8b.dtsi | 11 +++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
index 45619f6162c5..713a22456ff1 100644
--- a/arch/arm/boot/dts/meson8.dtsi
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -43,6 +43,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/meson8-gpio.h>
/include/ "meson.dtsi"
@@ -91,6 +93,13 @@
clock-frequency = <141666666>;
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -106,6 +115,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
spi_nor_pins: nor {
@@ -148,6 +158,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
index 41fd53671859..36a239a645f5 100644
--- a/arch/arm/boot/dts/meson8b.dtsi
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -44,6 +44,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/meson8b-clkc.h>
#include <dt-bindings/gpio/meson8b-gpio.h>
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
@@ -183,6 +185,13 @@
status = "disabled";
};
+ gpio_interrupt: interrupt-controller at c1109880 {
+ compatible = "amlogic,meson8b-gpio-intc";
+ reg = <0xc1109880 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pinctrl_cbus: pinctrl at c1109880 {
compatible = "amlogic,meson8b-cbus-pinctrl";
reg = <0xc1109880 0x10>;
@@ -198,6 +207,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
};
@@ -215,6 +225,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
--
2.7.4
^ permalink raw reply related
* [PATCH 8/9] ARM64: dts: amlogic: enable gpio interrupt controller on gxbb
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index aad639ab0112..5208cb80b55e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -141,6 +141,13 @@
#reset-cells = <1>;
};
+ gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,meson-gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
uart_B: serial at 84dc {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84dc 0x0 0x14>;
@@ -238,6 +245,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
uart_ao_a_pins: uart_ao_a {
@@ -343,6 +351,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ interrupt-parent = <&gpio_interrupt>;
};
emmc_pins: emmc {
--
2.7.4
^ permalink raw reply related
* [PATCH 7/9] ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson8 and meson8b SoC
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm/mach-meson/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index b6e3acc63e14..63157295cd9d 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -21,11 +21,13 @@ config MACH_MESON8
bool "Amlogic Meson8 SoCs support"
default ARCH_MESON
select MESON6_TIMER
+ select MESON_IRQ_GPIO
config MACH_MESON8B
bool "Amlogic Meson8b SoCs support"
default ARCH_MESON
select MESON6_TIMER
select COMMON_CLK_MESON8B
+ select MESON_IRQ_GPIO
endif
--
2.7.4
^ permalink raw reply related
* [PATCH 6/9] ARM64: meson: enable MESON_IRQ_GPIO in Kconfig
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Add select MESON_IRQ_GPIO in Kconfig for Amlogic's meson SoC family
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
arch/arm64/Kconfig.platforms | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index cfbdf02ef566..846479d4492d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -95,6 +95,7 @@ config ARCH_MESON
select PINCTRL_MESON
select COMMON_CLK_AMLOGIC
select COMMON_CLK_GXBB
+ select MESON_GPIO_IRQ
help
This enables support for the Amlogic S905 SoCs.
--
2.7.4
^ permalink raw reply related
* [PATCH 5/9] dt-bindings: pinctrl: meson: update gpio dt-bindings
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Add description for the interrupt-parent property of the gpio sub-node
If provided here, this property must be a phandle to an interrupt
controller suitable for meson pinctrl, like the meson gpio interrupt
controller.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
index fe7fe0b03cfb..39932c4dfb32 100644
--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -23,6 +23,10 @@ Required properties for sub-nodes are:
- gpio-controller: identifies the node as a gpio controller
- #gpio-cells: must be 2
+Optional property for sub-nodes is:
+ - interrupt-parent: must be a phandle to the meson gpio interrupt controller.
+ if this property is provided, enables gpio ability to generate interrupts
+
=== Other sub-nodes ===
Child nodes without the "gpio-controller" represent some desired
--
2.7.4
^ permalink raw reply related
* [PATCH 4/9] pinctrl: meson: allow gpio to request irq
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
Add the ability for gpio to request irq from the gpio interrupt controller
if present. We have to specificaly that the parent interrupt controller is
the gpio interrupt controller because gpio on meson SoCs can't generate
interrupt directly on the GIC.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/Kconfig | 2 +
drivers/pinctrl/meson/pinctrl-meson.c | 77 ++++++++++++++++++++++++++++++++++-
drivers/pinctrl/meson/pinctrl-meson.h | 1 +
3 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 0e75d94972ba..d5bfbfcddab0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -126,7 +126,9 @@ config PINCTRL_MESON
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
+ select IRQ_DOMAIN
select OF_GPIO
+ select OF_IRQ
select REGMAP_MMIO
config PINCTRL_OXNAS
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 57122eda155a..fd3c1d44978b 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -50,6 +50,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -481,6 +482,58 @@ static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
value ? BIT(bit) : 0);
}
+static int meson_gpio_to_hwirq(struct meson_bank *bank, unsigned int offset)
+{
+ unsigned int hwirq;
+
+ if (bank->irq_first < 0)
+ /* this bank cannot generate irqs */
+ return -1;
+
+ hwirq = offset - bank->first + bank->irq_first;
+
+ if (hwirq > bank->irq_last)
+ /* this pin cannot generate irqs */
+ return -1;
+
+ return hwirq;
+}
+
+static int meson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct meson_pinctrl *pc = gpiochip_get_data(chip);
+ struct meson_bank *bank;
+ struct irq_fwspec fwspec;
+ unsigned int hwirq;
+ int ret;
+
+ ret = meson_get_bank(pc, offset, &bank);
+ if (ret)
+ return ret;
+
+ /*
+ * The interrupt controller might be missing, in such case we can't
+ * provide an interrupt for a pin
+ */
+ if (is_fwnode_irqchip(pc->fwnode)) {
+ dev_info(pc->dev, "interrupt controller not found\n");
+ return 0;
+ }
+
+ hwirq = meson_gpio_to_hwirq(bank, offset);
+ if (hwirq < 0) {
+ dev_dbg(pc->dev, "no interrupt for pin %u\n", offset);
+ return 0;
+ }
+
+ fwspec.fwnode = pc->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_NONE;
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
struct meson_pinctrl *pc = gpiochip_get_data(chip);
@@ -539,6 +592,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
pc->chip.direction_output = meson_gpio_direction_output;
pc->chip.get = meson_gpio_get;
pc->chip.set = meson_gpio_set;
+ pc->chip.to_irq = meson_gpio_to_irq;
pc->chip.base = pc->data->pin_base;
pc->chip.ngpio = pc->data->num_pins;
pc->chip.can_sleep = false;
@@ -598,6 +652,27 @@ static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);
}
+static int meson_pinctrl_get_irq_gpio_intc(struct meson_pinctrl *pc,
+ struct device_node *node)
+{
+ struct device_node *np;
+
+ np = of_irq_find_parent(node);
+ if (unlikely(!np)) {
+ dev_err(pc->dev, "interrupt parent not found\n");
+ return -EINVAL;
+ }
+
+ if (!of_device_is_compatible(np, pc->data->irq_compat)) {
+ dev_info(pc->dev, "gpio interrupt disabled\n");
+ pc->fwnode = NULL;
+ }
+
+ pc->fwnode = of_node_to_fwnode(np);
+
+ return 0;
+}
+
static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
struct device_node *node)
{
@@ -643,7 +718,7 @@ static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
return PTR_ERR(pc->reg_gpio);
}
- return 0;
+ return meson_pinctrl_get_irq_gpio_intc(pc, gpio_np);
}
static int meson_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index b90d69e366df..2e6c83adbd1f 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -123,6 +123,7 @@ struct meson_pinctrl {
struct regmap *reg_gpio;
struct gpio_chip chip;
struct device_node *of_node;
+ struct fwnode_handle *fwnode;
};
#define PIN(x, b) (b + x)
--
2.7.4
^ permalink raw reply related
* [PATCH 3/9] pinctrl: meson: update pinctrl data with gpio irq data
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
This patch extends meson's pinctrl SoC specific data by adding the gpio
irq base number and the compatible controller for each SoC. This will
allow gpios to request an interrupt on the gpio interrupt controller
using this base irq number the pin offset inbank
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 24 +++++++++++----------
drivers/pinctrl/meson/pinctrl-meson.h | 16 +++++++++-----
drivers/pinctrl/meson/pinctrl-meson8.c | 22 ++++++++++---------
drivers/pinctrl/meson/pinctrl-meson8b.c | 34 +++++++++++++++++++++---------
4 files changed, 60 insertions(+), 36 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index c3928aa3fefa..ed8a1222de3b 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -715,24 +715,25 @@ static struct meson_pmx_func meson_gxbb_aobus_functions[] = {
};
static struct meson_bank meson_gxbb_periphs_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
- BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
- BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
- BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
- BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
- BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
- BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, EE_OFF), PIN(GPIOX_22, EE_OFF), 106, 128, 4, 0, 4, 0, 12, 0, 13, 0, 14, 0),
+ BANK("Y", PIN(GPIOY_0, EE_OFF), PIN(GPIOY_16, EE_OFF), 89, 105, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, EE_OFF), PIN(GPIODV_29, EE_OFF), 59, 88, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0),
+ BANK("H", PIN(GPIOH_0, EE_OFF), PIN(GPIOH_3, EE_OFF), 30, 33, 1, 20, 1, 20, 3, 20, 4, 20, 5, 20),
+ BANK("Z", PIN(GPIOZ_0, EE_OFF), PIN(GPIOZ_15, EE_OFF), 14, 29, 3, 0, 3, 0, 9, 0, 10, 0, 11, 0),
+ BANK("CARD", PIN(CARD_0, EE_OFF), PIN(CARD_6, EE_OFF), 52, 58, 2, 20, 2, 20, 6, 20, 7, 20, 8, 20),
+ BANK("BOOT", PIN(BOOT_0, EE_OFF), PIN(BOOT_17, EE_OFF), 34, 51, 2, 0, 2, 0, 6, 0, 7, 0, 8, 0),
+ BANK("CLK", PIN(GPIOCLK_0, EE_OFF), PIN(GPIOCLK_3, EE_OFF), 129, 132, 3, 28, 3, 28, 9, 28, 10, 28, 11, 28),
};
static struct meson_bank meson_gxbb_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, 0), PIN(GPIOAO_13, 0), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
.name = "periphs-banks",
+ .irq_compat = "amlogic,meson-gxbb-gpio-intc",
.pin_base = 14,
.pins = meson_gxbb_periphs_pins,
.groups = meson_gxbb_periphs_groups,
@@ -746,6 +747,7 @@ struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = {
struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = {
.name = "aobus-banks",
+ .irq_compat = "amlogic,meson-gxbb-gpio-intc",
.pin_base = 0,
.pins = meson_gxbb_aobus_pins,
.groups = meson_gxbb_aobus_groups,
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
index 98b5080650c1..b90d69e366df 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.h
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -81,6 +81,7 @@ enum meson_reg_type {
* @name: bank name
* @first: first pin of the bank
* @last: last pin of the bank
+ * @irq: hwirq base number of the bank
* @regs: array of register descriptors
*
* A bank represents a set of pins controlled by a contiguous set of
@@ -92,11 +93,14 @@ struct meson_bank {
const char *name;
unsigned int first;
unsigned int last;
+ int irq_first;
+ int irq_last;
struct meson_reg_desc regs[NUM_REG];
};
struct meson_pinctrl_data {
const char *name;
+ const char *irq_compat;
const struct pinctrl_pin_desc *pins;
struct meson_pmx_group *groups;
struct meson_pmx_func *funcs;
@@ -147,12 +151,14 @@ struct meson_pinctrl {
.num_groups = ARRAY_SIZE(fn ## _groups), \
}
-#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
{ \
- .name = n, \
- .first = f, \
- .last = l, \
- .regs = { \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .irq_first = fi, \
+ .irq_last = li, \
+ .regs = { \
[REG_PULLEN] = { per, peb }, \
[REG_PULL] = { pr, pb }, \
[REG_DIR] = { dr, db }, \
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
index 07f1cb21c1b8..eddab1091408 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -916,23 +916,24 @@ static struct meson_pmx_func meson8_aobus_functions[] = {
};
static struct meson_bank meson8_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 112, 133, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_16, 0), 95, 111, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_0, 0), PIN(GPIODV_29, 0), 65, 94, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 29, 38, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("Z", PIN(GPIOZ_0, 0), PIN(GPIOZ_14, 0), 14, 28, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 58, 64, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 39, 57, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
};
static struct meson_bank meson8_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
.name = "cbus-banks",
+ .irq_compat = "amlogic,meson8-gpio-intc",
.pin_base = 0,
.pins = meson8_cbus_pins,
.groups = meson8_cbus_groups,
@@ -946,6 +947,7 @@ struct meson_pinctrl_data meson8_cbus_pinctrl_data = {
struct meson_pinctrl_data meson8_aobus_pinctrl_data = {
.name = "ao-bank",
+ .irq_compat = "amlogic,meson8-gpio-intc",
.pin_base = 120,
.pins = meson8_aobus_pins,
.groups = meson8_aobus_groups,
diff --git a/drivers/pinctrl/meson/pinctrl-meson8b.c b/drivers/pinctrl/meson/pinctrl-meson8b.c
index 76f077f18193..d7505f492639 100644
--- a/drivers/pinctrl/meson/pinctrl-meson8b.c
+++ b/drivers/pinctrl/meson/pinctrl-meson8b.c
@@ -124,6 +124,12 @@ static const struct pinctrl_pin_desc meson8b_aobus_pins[] = {
MESON_PIN(GPIOAO_11, AO_OFF),
MESON_PIN(GPIOAO_12, AO_OFF),
MESON_PIN(GPIOAO_13, AO_OFF),
+
+ /*
+ * The following 2 pins are not mentionned in the public datasheet
+ * According to this datasheet, they can't be used with the gpio
+ * interrupt controller
+ */
MESON_PIN(GPIO_BSD_EN, AO_OFF),
MESON_PIN(GPIO_TEST_N, AO_OFF),
};
@@ -881,23 +887,30 @@ static struct meson_pmx_func meson8b_aobus_functions[] = {
};
static struct meson_bank meson8b_cbus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
- BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
- BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
- BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
- BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
- BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
- BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
+ /* name first last irq pullen pull dir out in */
+ BANK("X", PIN(GPIOX_0, 0), PIN(GPIOX_21, 0), 97, 118, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN(GPIOY_0, 0), PIN(GPIOY_14, 0), 80, 96, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN(GPIODV_9, 0), PIN(GPIODV_29, 0), 59, 79, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN(GPIOH_0, 0), PIN(GPIOH_9, 0), 14, 23, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("CARD", PIN(CARD_0, 0), PIN(CARD_6, 0), 43, 49, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN(BOOT_0, 0), PIN(BOOT_18, 0), 24, 42, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+
+ /*
+ * The following bank is not mentionned in the public datasheet
+ * There is no information whether it can be used with the gpio
+ * interrupt controller
+ */
+ BANK("DIF", PIN(DIF_0_P, 0), PIN(DIF_4_N, 0), -1, -1, 5, 8, 5, 8, 12, 12, 13, 12, 14, 12),
};
static struct meson_bank meson8b_aobus_banks[] = {
- /* name first last pullen pull dir out in */
- BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+ /* name first last irq pullen pull dir out in */
+ BANK("AO", PIN(GPIOAO_0, AO_OFF), PIN(GPIO_TEST_N, AO_OFF), 0, 13, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
};
struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
.name = "cbus-banks",
+ .irq_compat = "amlogic,meson8b-gpio-intc",
.pin_base = 0,
.pins = meson8b_cbus_pins,
.groups = meson8b_cbus_groups,
@@ -911,6 +924,7 @@ struct meson_pinctrl_data meson8b_cbus_pinctrl_data = {
struct meson_pinctrl_data meson8b_aobus_pinctrl_data = {
.name = "aobus-banks",
+ .irq_compat = "amlogic,meson8b-gpio-intc",
.pin_base = 130,
.pins = meson8b_aobus_pins,
.groups = meson8b_aobus_groups,
--
2.7.4
^ permalink raw reply related
* [PATCH 2/9] dt-bindings: interrupt-controller: add DT binding for meson GPIO interrupt controller
From: Jerome Brunet @ 2016-10-19 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476871709-8359-1-git-send-email-jbrunet@baylibre.com>
This commit adds the device tree bindings description for Amlogic's GPIO
interrupt controller available on the meson8, meson8b and gxbb SoC families
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
---
Rob, I did not include the Ack you gave for the RFC as bindings have slightly
changed. Only the interrupt property has be removed following a discussion I
had with Marc.
.../amlogic,meson-gpio-intc.txt | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
new file mode 100644
index 000000000000..2464d9a0865d
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt
@@ -0,0 +1,31 @@
+Amlogic meson GPIO interrupt controller
+
+Meson SoCs contains an interrupt controller which is able watch the SoC pads
+and generate an interrupt on edges or level. The controller is essentially a
+256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge
+or level and polarity. We don?t expose all 256 mux inputs because the
+documentation shows that upper part is not mapped to any pad. The actual number
+of interrupt exposed depends on the SoC.
+
+Required properties:
+
+- compatible : should be either
+ "amlogic,meson8-gpio-intc? for meson8 SoCs (AML7826MX) or
+ ?amlogic,meson8b-gpio-intc? for meson8b SoCs (S805) or
+ ?amlogic,meson-gxbb-gpio-intc? for GXBB SoCs (S905)
+- interrupt-parent : a phandle to the GIC the interrupts are routed to.
+ Usually this is provided at the root level of the device tree as it is
+ common to most of the SoC
+- reg : Specifies base physical address and size of the registers.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value must be 2.
+
+Example:
+
+gpio_interrupt: interrupt-controller at 9880 {
+ compatible = "amlogic,meson-gxbb-gpio-intc";
+ reg = <0x0 0x9880 0x0 0x10>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox