* [PATCH v2 0/8] ARM: sun9i: SMP support with Multi-Cluster Power Management
From: Maxime Ripard @ 2018-01-04 14:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>
On Thu, Jan 04, 2018 at 10:37:46PM +0800, Chen-Yu Tsai wrote:
> This is v2 of my sun9i SMP support with MCPM series which was started
> over two years ago [1]. We've tried to implement PSCI for both the A80
> and A83T. Results were not promising. The issue is that these two chips
> have a broken security extensions implementation. If a specific bit is
> not burned in its e-fuse, most if not all security protections don't
> work [2]. Even worse, non-secure access to the GIC become secure. This
> requires a crazy workaround in the GIC driver which probably doesn't work
> in all cases [3].
>
> Nicolas mentioned that the MCPM framework is likely overkill in our
> case [4]. However the framework does provide cluster/core state tracking
> and proper sequencing of cache related operations. We could rework
> the code to use standard smp_ops, but I would like to actually get
> a working version in first.
>
> Much of the sunxi-specific MCPM code is derived from Allwinner code and
> documentation, with some references to the other MCPM implementations,
> as well as the Cortex's Technical Reference Manuals for the power
> sequencing info.
>
> One major difference compared to other platforms is we currently do not
> have a standalone PMU or other embedded firmware to do the actually power
> sequencing. All power/reset control is done by the kernel. Nicolas
> mentioned that a new optional callback should be added in cases where the
> kernel has to do the actual power down [5]. For now however I'm using a
> dedicated single thread workqueue. CPU and cluster power off work is
> queued from the .{cpu,cluster}_powerdown_prepare callbacks. This solution
> is somewhat heavy, as I have a total of 10 static work structs. It might
> also be a bit racy, as nothing prevents the system from bringing a core
> back before the asynchronous work shuts it down. This would likely
> happen under a heavily loaded system with a scheduler that brings cores
> in and out of the system frequently. In simple use-cases it performs OK.
It all looks sane to me
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/8ea853e2/attachment.sig>
^ permalink raw reply
* [PATCH 1/2] ARM: dts: sunxi: Switch MMC nodes away from cd-inverted property
From: Maxime Ripard @ 2018-01-04 15:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171222205738.2389-1-tuomas@tuxera.com>
On Fri, Dec 22, 2017 at 10:57:37PM +0200, Tuomas Tynkkynen wrote:
> Using the cd-inverted property is not useful when GPIOs are used as card
> detects since the polarity can be specified with the usual
> GPIO_ACTIVE_(HIGH|LOW) GPIO flags. It has also caused confusion for
> U-Boot developers, so migrate all sunxi boards away from cd-inverted.
>
> Signed-off-by: Tuomas Tynkkynen <tuomas@tuxera.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/e901dee6/attachment.sig>
^ permalink raw reply
* [PATCH 2/2] arm64: dts: sunxi: Switch MMC nodes away from cd-inverted property
From: Maxime Ripard @ 2018-01-04 15:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171222205738.2389-2-tuomas@tuxera.com>
On Fri, Dec 22, 2017 at 10:57:38PM +0200, Tuomas Tynkkynen wrote:
> Using the cd-inverted property is not useful when GPIOs are used as card
> detects since the polarity can be specified with the usual
> GPIO_ACTIVE_(HIGH|LOW) GPIO flags. It has also caused confusion for
> U-Boot developers, so migrate all sunxi boards away from cd-inverted.
>
> Signed-off-by: Tuomas Tynkkynen <tuomas@tuxera.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/4ed5a34e/attachment.sig>
^ permalink raw reply
* [PATCH 1/2] clk: imx: imx7d: add the snvs clock
From: Anson Huang @ 2018-01-04 15:06 UTC (permalink / raw)
To: linux-arm-kernel
According to the i.MX7D Reference Manual,
SNVS block has a clock gate, accessing SNVS block
would need this clock gate to be enabled, add it
into clock tree so that SNVS module driver can
operate this clock gate.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
drivers/clk/imx/clk-imx7d.c | 1 +
include/dt-bindings/clock/imx7d-clock.h | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index 992938b..a284c6f 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -799,6 +799,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
+ clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0);
clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0);
clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
diff --git a/include/dt-bindings/clock/imx7d-clock.h b/include/dt-bindings/clock/imx7d-clock.h
index e2f99ae..dc51904 100644
--- a/include/dt-bindings/clock/imx7d-clock.h
+++ b/include/dt-bindings/clock/imx7d-clock.h
@@ -452,5 +452,6 @@
#define IMX7D_OCOTP_CLK 439
#define IMX7D_NAND_RAWNAND_CLK 440
#define IMX7D_NAND_USDHC_BUS_RAWNAND_CLK 441
-#define IMX7D_CLK_END 442
+#define IMX7D_SNVS_CLK 442
+#define IMX7D_CLK_END 443
#endif /* __DT_BINDINGS_CLOCK_IMX7D_H */
--
1.9.1
^ permalink raw reply related
* [PATCH 2/2] ARM: dts: imx7s: add snvs rtc clock
From: Anson Huang @ 2018-01-04 15:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078402-22135-1-git-send-email-Anson.Huang@nxp.com>
Add i.MX7 SNVS RTC clock.
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
arch/arm/boot/dts/imx7s.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/imx7s.dtsi b/arch/arm/boot/dts/imx7s.dtsi
index e718fd2..f9b97f3 100644
--- a/arch/arm/boot/dts/imx7s.dtsi
+++ b/arch/arm/boot/dts/imx7s.dtsi
@@ -534,6 +534,8 @@
offset = <0x34>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_SNVS_CLK>;
+ clock-names = "snvs-rtc";
};
snvs_poweroff: snvs-poweroff {
--
1.9.1
^ permalink raw reply related
* [PATCH 00/11] arm64 kpti hardening and variant 2 workarounds
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
This set of patches builds on top of the arm64 kpti patches[1] queued for
4.16 and further hardens the arm64 Linux kernel against the side-channel
attacks recently published by Google Project Zero.
In particular, the series does the following:
* Enable kpti by default on arm64, based on the value of ID_AA64PFR0_EL1.CSV3
* Prevent speculative resteering of the indirect branch in the exception
trampoline page, which resides at a fixed virtual address to avoid a
KASLR leak
* Add hooks to changes of context where the branch predictor could
theoretically resteer the speculative instruction stream having been trained
by userspace or a guest OS. These hooks are signal delivery (to prevent
training the branch predictor on kernel addresses from userspace),
switch_mm (return to user if SW PAN is enabled) and exit from a guest VM.
* Implement a dummy PSCI "VERSION" call as the hook for affected Cortex-A
CPUs. This will invalidate the predictor state with the latest Arm Trusted
Firmware patches which will appear at [2] and SoC vendors with affected
CPUs are strongly encouraged to update. We plan to switch to a more
efficient, special-purpose call when it is available and the PSCI spec
has been updated accordingly.
I'd like to get this in for 4.16, but that doesn't mean we can't improve
it further once it's merged.
For more information about the impact of this issue and the software migitations
for Arm processors, please see http://www.arm.com/security-update.
Thanks,
Will
[1] https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/tag/?h=kpti-base
[2] https://github.com/ARM-software/arm-trusted-firmware/wiki/ARM-Trusted-Firmware-Security-Advisory-TFV-6
--->8
Marc Zyngier (3):
arm64: Move post_ttbr_update_workaround to C code
arm64: KVM: Use per-CPU vector when BP hardening is enabled
arm64: KVM: Make PSCI_VERSION a fast path
Will Deacon (8):
arm64: use RET instruction for exiting the trampoline
arm64: Kconfig: Reword UNMAP_KERNEL_AT_EL0 kconfig entry
arm64: Take into account ID_AA64PFR0_EL1.CSV3
arm64: cpufeature: Pass capability structure to ->enable callback
drivers/firmware: Expose psci_get_version through psci_ops structure
arm64: Add skeleton to harden the branch predictor against aliasing
attacks
arm64: cputype: Add missing MIDR values for Cortex-A72 and Cortex-A75
arm64: Implement branch predictor hardening for affected Cortex-A CPUs
arch/arm/include/asm/kvm_mmu.h | 10 ++++
arch/arm64/Kconfig | 30 +++++++---
arch/arm64/include/asm/assembler.h | 13 -----
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/cputype.h | 4 ++
arch/arm64/include/asm/kvm_mmu.h | 38 ++++++++++++
arch/arm64/include/asm/mmu.h | 37 ++++++++++++
arch/arm64/include/asm/sysreg.h | 2 +
arch/arm64/kernel/Makefile | 4 ++
arch/arm64/kernel/bpi.S | 79 +++++++++++++++++++++++++
arch/arm64/kernel/cpu_errata.c | 116 +++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/cpufeature.c | 12 +++-
arch/arm64/kernel/entry.S | 7 ++-
arch/arm64/kvm/hyp/switch.c | 15 ++++-
arch/arm64/mm/context.c | 11 ++++
arch/arm64/mm/fault.c | 1 +
arch/arm64/mm/proc.S | 3 +-
drivers/firmware/psci.c | 2 +
include/linux/psci.h | 1 +
virt/kvm/arm/arm.c | 8 ++-
20 files changed, 366 insertions(+), 30 deletions(-)
create mode 100644 arch/arm64/kernel/bpi.S
--
2.1.4
^ permalink raw reply
* [PATCH 01/11] arm64: use RET instruction for exiting the trampoline
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Speculation attacks against the entry trampoline can potentially resteer
the speculative instruction stream through the indirect branch and into
arbitrary gadgets within the kernel.
This patch defends against these attacks by forcing a misprediction
through the return stack: a dummy BL instruction loads an entry into
the stack, so that the predicted program flow of the subsequent RET
instruction is to a branch-to-self instruction which is finally resolved
as a branch to the kernel vectors with speculation suppressed.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/entry.S | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 031392ee5f47..b9feb587294d 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -1029,6 +1029,9 @@ alternative_else_nop_endif
.if \regsize == 64
msr tpidrro_el0, x30 // Restored in kernel_ventry
.endif
+ bl 2f
+ b .
+2:
tramp_map_kernel x30
#ifdef CONFIG_RANDOMIZE_BASE
adr x30, tramp_vectors + PAGE_SIZE
@@ -1041,7 +1044,7 @@ alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
msr vbar_el1, x30
add x30, x30, #(1b - tramp_vectors)
isb
- br x30
+ ret
.endm
.macro tramp_exit, regsize = 64
--
2.1.4
^ permalink raw reply related
* [PATCH 02/11] arm64: Kconfig: Reword UNMAP_KERNEL_AT_EL0 kconfig entry
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Although CONFIG_UNMAP_KERNEL_AT_EL0 does make KASLR more robust, it's
actually more useful as a mitigation against speculation attacks that
can leak arbitrary kernel data to userspace through speculation.
Reword the Kconfig help message to reflect this, and make the option
depend on EXPERT so that it is on by default for the majority of users.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3af1657fcac3..efaaa3a66b95 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -834,15 +834,14 @@ config FORCE_MAX_ZONEORDER
4M allocations matching the default size used by generic code.
config UNMAP_KERNEL_AT_EL0
- bool "Unmap kernel when running in userspace (aka \"KAISER\")"
+ bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT
default y
help
- Some attacks against KASLR make use of the timing difference between
- a permission fault which could arise from a page table entry that is
- present in the TLB, and a translation fault which always requires a
- page table walk. This option defends against these attacks by unmapping
- the kernel whilst running in userspace, therefore forcing translation
- faults for all of kernel space.
+ Speculation attacks against some high-performance processors can
+ be used to bypass MMU permission checks and leak kernel data to
+ userspace. This can be defended against by unmapping the kernel
+ when running in userspace, mapping it back in on exception entry
+ via a trampoline page in the vector table.
If unsure, say Y.
--
2.1.4
^ permalink raw reply related
* [PATCH 03/11] arm64: Take into account ID_AA64PFR0_EL1.CSV3
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
For non-KASLR kernels where the KPTI behaviour has not been overridden
on the command line we can use ID_AA64PFR0_EL1.CSV3 to determine whether
or not we should unmap the kernel whilst running at EL0.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/kernel/cpufeature.c | 7 ++++++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 08cc88574659..ae519bbd3f9e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -437,6 +437,7 @@
#define ID_AA64ISAR1_DPB_SHIFT 0
/* id_aa64pfr0 */
+#define ID_AA64PFR0_CSV3_SHIFT 60
#define ID_AA64PFR0_SVE_SHIFT 32
#define ID_AA64PFR0_GIC_SHIFT 24
#define ID_AA64PFR0_ASIMD_SHIFT 20
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9f0545dfe497..e11c11bb5b02 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -145,6 +145,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
};
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_GIC_SHIFT, 4, 0),
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
@@ -851,6 +852,8 @@ static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */
static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
int __unused)
{
+ u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
/* Forced on command line? */
if (__kpti_forced) {
pr_info_once("kernel page table isolation forced %s by command line option\n",
@@ -862,7 +865,9 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
return true;
- return false;
+ /* Defer to CPU feature registers */
+ return !cpuid_feature_extract_unsigned_field(pfr0,
+ ID_AA64PFR0_CSV3_SHIFT);
}
static int __init parse_kpti(char *str)
--
2.1.4
^ permalink raw reply related
* [PATCH 04/11] arm64: cpufeature: Pass capability structure to ->enable callback
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
In order to invoke the CPU capability ->matches callback from the ->enable
callback for applying local-CPU workarounds, we need a handle on the
capability structure.
This patch passes a pointer to the capability structure to the ->enable
callback.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/cpufeature.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index e11c11bb5b02..6133c14b9b01 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1151,7 +1151,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
* uses an IPI, giving us a PSTATE that disappears when
* we return.
*/
- stop_machine(caps->enable, NULL, cpu_online_mask);
+ stop_machine(caps->enable, (void *)caps, cpu_online_mask);
}
}
}
@@ -1194,7 +1194,7 @@ verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
cpu_die_early();
}
if (caps->enable)
- caps->enable(NULL);
+ caps->enable((void *)caps);
}
}
--
2.1.4
^ permalink raw reply related
* [PATCH 05/11] drivers/firmware: Expose psci_get_version through psci_ops structure
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Entry into recent versions of ARM Trusted Firmware will invalidate the CPU
branch predictor state in order to protect against aliasing attacks.
This patch exposes the PSCI "VERSION" function via psci_ops, so that it
can be invoked outside of the PSCI driver where necessary.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
drivers/firmware/psci.c | 2 ++
include/linux/psci.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index d687ca3d5049..8b25d31e8401 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -496,6 +496,8 @@ static void __init psci_init_migrate(void)
static void __init psci_0_2_set_functions(void)
{
pr_info("Using standard PSCI v0.2 function IDs\n");
+ psci_ops.get_version = psci_get_version;
+
psci_function_id[PSCI_FN_CPU_SUSPEND] =
PSCI_FN_NATIVE(0_2, CPU_SUSPEND);
psci_ops.cpu_suspend = psci_cpu_suspend;
diff --git a/include/linux/psci.h b/include/linux/psci.h
index bdea1cb5e1db..6306ab10af18 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -26,6 +26,7 @@ int psci_cpu_init_idle(unsigned int cpu);
int psci_cpu_suspend_enter(unsigned long index);
struct psci_operations {
+ u32 (*get_version)(void);
int (*cpu_suspend)(u32 state, unsigned long entry_point);
int (*cpu_off)(u32 state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
--
2.1.4
^ permalink raw reply related
* [PATCH 06/11] arm64: Move post_ttbr_update_workaround to C code
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
From: Marc Zyngier <marc.zyngier@arm.com>
We will soon need to invoke a CPU-specific function pointer after changing
page tables, so move post_ttbr_update_workaround out into C code to make
this possible.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/assembler.h | 13 -------------
arch/arm64/kernel/entry.S | 2 +-
arch/arm64/mm/context.c | 9 +++++++++
arch/arm64/mm/proc.S | 3 +--
4 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index c45bc94f15d0..cee60ce0da52 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -476,17 +476,4 @@ alternative_endif
mrs \rd, sp_el0
.endm
-/*
- * Errata workaround post TTBRx_EL1 update.
- */
- .macro post_ttbr_update_workaround
-#ifdef CONFIG_CAVIUM_ERRATUM_27456
-alternative_if ARM64_WORKAROUND_CAVIUM_27456
- ic iallu
- dsb nsh
- isb
-alternative_else_nop_endif
-#endif
- .endm
-
#endif /* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index b9feb587294d..6aa112baf601 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -277,7 +277,7 @@ alternative_else_nop_endif
* Cavium erratum 27456 (broadcast TLBI instructions may cause I-cache
* corruption).
*/
- post_ttbr_update_workaround
+ bl post_ttbr_update_workaround
.endif
1:
.if \el != 0
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 1cb3bc92ae5c..c1e3b6479c8f 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -239,6 +239,15 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
cpu_switch_mm(mm->pgd, mm);
}
+/* Errata workaround post TTBRx_EL1 update. */
+asmlinkage void post_ttbr_update_workaround(void)
+{
+ asm volatile(ALTERNATIVE("nop; nop; nop",
+ "ic iallu; dsb nsh; isb",
+ ARM64_WORKAROUND_CAVIUM_27456,
+ CONFIG_CAVIUM_ERRATUM_27456));
+}
+
static int asids_init(void)
{
asid_bits = get_cpu_asid_bits();
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 3146dc96f05b..6affb68a9a14 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -145,8 +145,7 @@ ENTRY(cpu_do_switch_mm)
isb
msr ttbr0_el1, x0 // now update TTBR0
isb
- post_ttbr_update_workaround
- ret
+ b post_ttbr_update_workaround // Back to C code...
ENDPROC(cpu_do_switch_mm)
.pushsection ".idmap.text", "ax"
--
2.1.4
^ permalink raw reply related
* [PATCH 07/11] arm64: Add skeleton to harden the branch predictor against aliasing attacks
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Aliasing attacks against CPU branch predictors can allow an attacker to
redirect speculative control flow on some CPUs and potentially divulge
information from one context to another.
This patch adds initial skeleton code behind a new Kconfig option to
enable implementation-specific mitigations against these attacks for
CPUs that are affected.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/Kconfig | 17 +++++++++
arch/arm64/include/asm/cpucaps.h | 3 +-
arch/arm64/include/asm/mmu.h | 37 ++++++++++++++++++++
arch/arm64/include/asm/sysreg.h | 1 +
arch/arm64/kernel/Makefile | 4 +++
arch/arm64/kernel/bpi.S | 55 +++++++++++++++++++++++++++++
arch/arm64/kernel/cpu_errata.c | 74 ++++++++++++++++++++++++++++++++++++++++
arch/arm64/kernel/cpufeature.c | 1 +
arch/arm64/mm/context.c | 2 ++
arch/arm64/mm/fault.c | 1 +
10 files changed, 194 insertions(+), 1 deletion(-)
create mode 100644 arch/arm64/kernel/bpi.S
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index efaaa3a66b95..cea44b95187c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -845,6 +845,23 @@ config UNMAP_KERNEL_AT_EL0
If unsure, say Y.
+config HARDEN_BRANCH_PREDICTOR
+ bool "Harden the branch predictor against aliasing attacks" if EXPERT
+ default y
+ help
+ Speculation attacks against some high-performance processors rely on
+ being able to manipulate the branch predictor for a victim context by
+ executing aliasing branches in the attacker context. Such attacks
+ can be partially mitigated against by clearing internal branch
+ predictor state and limiting the prediction logic in some situations.
+
+ This config option will take CPU-specific actions to harden the
+ branch predictor against aliasing attacks and may rely on specific
+ instruction sequences or control bits being set by the system
+ firmware.
+
+ If unsure, say Y.
+
menuconfig ARMV8_DEPRECATED
bool "Emulate deprecated/obsolete ARMv8 instructions"
depends on COMPAT
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index b4537ffd1018..51616e77fe6b 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -42,7 +42,8 @@
#define ARM64_HAS_DCPOP 21
#define ARM64_SVE 22
#define ARM64_UNMAP_KERNEL_AT_EL0 23
+#define ARM64_HARDEN_BRANCH_PREDICTOR 24
-#define ARM64_NCAPS 24
+#define ARM64_NCAPS 25
#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index 6f7bdb89817f..6dd83d75b82a 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -41,6 +41,43 @@ static inline bool arm64_kernel_unmapped_at_el0(void)
cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
}
+typedef void (*bp_hardening_cb_t)(void);
+
+struct bp_hardening_data {
+ int hyp_vectors_slot;
+ bp_hardening_cb_t fn;
+};
+
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[];
+
+DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
+
+static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
+{
+ return this_cpu_ptr(&bp_hardening_data);
+}
+
+static inline void arm64_apply_bp_hardening(void)
+{
+ struct bp_hardening_data *d;
+
+ if (!cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR))
+ return;
+
+ d = arm64_get_bp_hardening_data();
+ if (d->fn)
+ d->fn();
+}
+#else
+static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
+{
+ return NULL;
+}
+
+static inline void arm64_apply_bp_hardening(void) { }
+#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
+
extern void paging_init(void);
extern void bootmem_init(void);
extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index ae519bbd3f9e..871744973ece 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -438,6 +438,7 @@
/* id_aa64pfr0 */
#define ID_AA64PFR0_CSV3_SHIFT 60
+#define ID_AA64PFR0_CSV2_SHIFT 56
#define ID_AA64PFR0_SVE_SHIFT 32
#define ID_AA64PFR0_GIC_SHIFT 24
#define ID_AA64PFR0_ASIMD_SHIFT 20
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 067baace74a0..0c760db04858 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -53,6 +53,10 @@ arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o
arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
+ifeq ($(CONFIG_KVM),y)
+arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o
+endif
+
obj-y += $(arm64-obj-y) vdso/ probes/
obj-m += $(arm64-obj-m)
head-y := head.o
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
new file mode 100644
index 000000000000..06a931eb2673
--- /dev/null
+++ b/arch/arm64/kernel/bpi.S
@@ -0,0 +1,55 @@
+/*
+ * Contains CPU specific branch predictor invalidation sequences
+ *
+ * Copyright (C) 2018 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+.macro ventry target
+ .rept 31
+ nop
+ .endr
+ b \target
+.endm
+
+.macro vectors target
+ ventry \target + 0x000
+ ventry \target + 0x080
+ ventry \target + 0x100
+ ventry \target + 0x180
+
+ ventry \target + 0x200
+ ventry \target + 0x280
+ ventry \target + 0x300
+ ventry \target + 0x380
+
+ ventry \target + 0x400
+ ventry \target + 0x480
+ ventry \target + 0x500
+ ventry \target + 0x580
+
+ ventry \target + 0x600
+ ventry \target + 0x680
+ ventry \target + 0x700
+ ventry \target + 0x780
+.endm
+
+ .align 11
+ENTRY(__bp_harden_hyp_vecs_start)
+ .rept 4
+ vectors __kvm_hyp_vector
+ .endr
+ENTRY(__bp_harden_hyp_vecs_end)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 0e27f86ee709..16ea5c6f314e 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -46,6 +46,80 @@ static int cpu_enable_trap_ctr_access(void *__unused)
return 0;
}
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+
+DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
+
+#ifdef CONFIG_KVM
+static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
+ const char *hyp_vecs_end)
+{
+ void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
+ int i;
+
+ for (i = 0; i < SZ_2K; i += 0x80)
+ memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
+
+ flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
+}
+
+static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
+ const char *hyp_vecs_start,
+ const char *hyp_vecs_end)
+{
+ static int last_slot = -1;
+ static DEFINE_SPINLOCK(bp_lock);
+ int cpu, slot = -1;
+
+ spin_lock(&bp_lock);
+ for_each_possible_cpu(cpu) {
+ if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
+ slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
+ break;
+ }
+ }
+
+ if (slot == -1) {
+ last_slot++;
+ BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start)
+ / SZ_2K) <= last_slot);
+ slot = last_slot;
+ __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
+ }
+
+ __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
+ __this_cpu_write(bp_hardening_data.fn, fn);
+ spin_unlock(&bp_lock);
+}
+#else
+static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
+ const char *hyp_vecs_start,
+ const char *hyp_vecs_end)
+{
+ __this_cpu_write(bp_hardening_data.fn, fn);
+}
+#endif /* CONFIG_KVM */
+
+static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
+ bp_hardening_cb_t fn,
+ const char *hyp_vecs_start,
+ const char *hyp_vecs_end)
+{
+ u64 pfr0;
+
+ if (!entry->matches(entry, SCOPE_LOCAL_CPU))
+ return;
+
+ pfr0 = read_cpuid(ID_AA64PFR0_EL1);
+ if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT))
+ return;
+
+ __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
+}
+#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
+
#define MIDR_RANGE(model, min, max) \
.def_scope = SCOPE_LOCAL_CPU, \
.matches = is_affected_midr_range, \
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6133c14b9b01..19ed09b0bb24 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -146,6 +146,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_GIC_SHIFT, 4, 0),
S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index c1e3b6479c8f..f1d99ffc77d1 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -246,6 +246,8 @@ asmlinkage void post_ttbr_update_workaround(void)
"ic iallu; dsb nsh; isb",
ARM64_WORKAROUND_CAVIUM_27456,
CONFIG_CAVIUM_ERRATUM_27456));
+
+ arm64_apply_bp_hardening();
}
static int asids_init(void)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 22168cd0dde7..5203b6040cb6 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -318,6 +318,7 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
lsb = PAGE_SHIFT;
si.si_addr_lsb = lsb;
+ arm64_apply_bp_hardening();
force_sig_info(sig, &si, tsk);
}
--
2.1.4
^ permalink raw reply related
* [PATCH 08/11] arm64: KVM: Use per-CPU vector when BP hardening is enabled
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
From: Marc Zyngier <marc.zyngier@arm.com>
Now that we have per-CPU vectors, let's plug then in the KVM/arm64 code.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm/include/asm/kvm_mmu.h | 10 ++++++++++
arch/arm64/include/asm/kvm_mmu.h | 38 ++++++++++++++++++++++++++++++++++++++
arch/arm64/kvm/hyp/switch.c | 2 +-
virt/kvm/arm/arm.c | 8 +++++++-
4 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index fa6f2174276b..eb46fc81a440 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -221,6 +221,16 @@ static inline unsigned int kvm_get_vmid_bits(void)
return 8;
}
+static inline void *kvm_get_hyp_vector(void)
+{
+ return kvm_ksym_ref(__kvm_hyp_vector);
+}
+
+static inline int kvm_map_vectors(void)
+{
+ return 0;
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 672c8684d5c2..2d6d4bd9de52 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -309,5 +309,43 @@ static inline unsigned int kvm_get_vmid_bits(void)
return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
}
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+#include <asm/mmu.h>
+
+static inline void *kvm_get_hyp_vector(void)
+{
+ struct bp_hardening_data *data = arm64_get_bp_hardening_data();
+ void *vect = kvm_ksym_ref(__kvm_hyp_vector);
+
+ if (data->fn) {
+ vect = __bp_harden_hyp_vecs_start +
+ data->hyp_vectors_slot * SZ_2K;
+
+ if (!has_vhe())
+ vect = lm_alias(vect);
+ }
+
+ return vect;
+}
+
+static inline int kvm_map_vectors(void)
+{
+ return create_hyp_mappings(kvm_ksym_ref(__bp_harden_hyp_vecs_start),
+ kvm_ksym_ref(__bp_harden_hyp_vecs_end),
+ PAGE_HYP_EXEC);
+}
+
+#else
+static inline void *kvm_get_hyp_vector(void)
+{
+ return kvm_ksym_ref(__kvm_hyp_vector);
+}
+
+static inline int kvm_map_vectors(void)
+{
+ return 0;
+}
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index f7c651f3a8c0..8d4f3c9d6dc4 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -52,7 +52,7 @@ static void __hyp_text __activate_traps_vhe(void)
val &= ~(CPACR_EL1_FPEN | CPACR_EL1_ZEN);
write_sysreg(val, cpacr_el1);
- write_sysreg(__kvm_hyp_vector, vbar_el1);
+ write_sysreg(kvm_get_hyp_vector(), vbar_el1);
}
static void __hyp_text __activate_traps_nvhe(void)
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 6b60c98a6e22..1c9fdb6db124 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1158,7 +1158,7 @@ static void cpu_init_hyp_mode(void *dummy)
pgd_ptr = kvm_mmu_get_httbr();
stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
hyp_stack_ptr = stack_page + PAGE_SIZE;
- vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
+ vector_ptr = (unsigned long)kvm_get_hyp_vector();
__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
__cpu_init_stage2();
@@ -1403,6 +1403,12 @@ static int init_hyp_mode(void)
goto out_err;
}
+ err = kvm_map_vectors();
+ if (err) {
+ kvm_err("Cannot map vectors\n");
+ goto out_err;
+ }
+
/*
* Map the Hyp stack pages
*/
--
2.1.4
^ permalink raw reply related
* [PATCH 09/11] arm64: KVM: Make PSCI_VERSION a fast path
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
From: Marc Zyngier <marc.zyngier@arm.com>
For those CPUs that require PSCI to perform a BP invalidation,
going all the way to the PSCI code for not much is a waste of
precious cycles. Let's terminate that call as early as possible.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kvm/hyp/switch.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 8d4f3c9d6dc4..4d273f6d0e69 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/jump_label.h>
+#include <uapi/linux/psci.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
@@ -341,6 +342,18 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
goto again;
+ if (exit_code == ARM_EXCEPTION_TRAP &&
+ (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 ||
+ kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) &&
+ vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) {
+ u64 val = PSCI_RET_NOT_SUPPORTED;
+ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+ val = 2;
+
+ vcpu_set_reg(vcpu, 0, val);
+ goto again;
+ }
+
if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
exit_code == ARM_EXCEPTION_TRAP) {
bool valid;
--
2.1.4
^ permalink raw reply related
* [PATCH 10/11] arm64: cputype: Add missing MIDR values for Cortex-A72 and Cortex-A75
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Hook up MIDR values for the Cortex-A72 and Cortex-A75 CPUs, since they
will soon need MIDR matches for hardening the branch predictor.
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/cputype.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 235e77d98261..84385b94e70b 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -79,8 +79,10 @@
#define ARM_CPU_PART_AEM_V8 0xD0F
#define ARM_CPU_PART_FOUNDATION 0xD00
#define ARM_CPU_PART_CORTEX_A57 0xD07
+#define ARM_CPU_PART_CORTEX_A72 0xD08
#define ARM_CPU_PART_CORTEX_A53 0xD03
#define ARM_CPU_PART_CORTEX_A73 0xD09
+#define ARM_CPU_PART_CORTEX_A75 0xD0A
#define APM_CPU_PART_POTENZA 0x000
@@ -94,7 +96,9 @@
#define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
#define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
+#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72)
#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
+#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75)
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
--
2.1.4
^ permalink raw reply related
* [PATCH 11/11] arm64: Implement branch predictor hardening for affected Cortex-A CPUs
From: Will Deacon @ 2018-01-04 15:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-1-git-send-email-will.deacon@arm.com>
Cortex-A57, A72, A73 and A75 are susceptible to branch predictor aliasing
and can theoretically be attacked by malicious code.
This patch implements a PSCI-based mitigation for these CPUs when available.
The call into firmware will invalidate the branch predictor state, preventing
any malicious entries from affecting other victim contexts.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/kernel/bpi.S | 24 ++++++++++++++++++++++++
arch/arm64/kernel/cpu_errata.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index 06a931eb2673..2b10d52a0321 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -53,3 +53,27 @@ ENTRY(__bp_harden_hyp_vecs_start)
vectors __kvm_hyp_vector
.endr
ENTRY(__bp_harden_hyp_vecs_end)
+ENTRY(__psci_hyp_bp_inval_start)
+ stp x0, x1, [sp, #-16]!
+ stp x2, x3, [sp, #-16]!
+ stp x4, x5, [sp, #-16]!
+ stp x6, x7, [sp, #-16]!
+ stp x8, x9, [sp, #-16]!
+ stp x10, x11, [sp, #-16]!
+ stp x12, x13, [sp, #-16]!
+ stp x14, x15, [sp, #-16]!
+ stp x16, x17, [sp, #-16]!
+ stp x18, x19, [sp, #-16]!
+ mov x0, #0x84000000
+ smc #0
+ ldp x18, x19, [sp], #16
+ ldp x16, x17, [sp], #16
+ ldp x14, x15, [sp], #16
+ ldp x12, x13, [sp], #16
+ ldp x10, x11, [sp], #16
+ ldp x8, x9, [sp], #16
+ ldp x6, x7, [sp], #16
+ ldp x4, x5, [sp], #16
+ ldp x2, x3, [sp], #16
+ ldp x0, x1, [sp], #16
+ENTRY(__psci_hyp_bp_inval_end)
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 16ea5c6f314e..cb0fb3796bb8 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -53,6 +53,8 @@ static int cpu_enable_trap_ctr_access(void *__unused)
DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
#ifdef CONFIG_KVM
+extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
+
static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
const char *hyp_vecs_end)
{
@@ -94,6 +96,9 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
spin_unlock(&bp_lock);
}
#else
+#define __psci_hyp_bp_inval_start NULL
+#define __psci_hyp_bp_inval_end NULL
+
static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
const char *hyp_vecs_start,
const char *hyp_vecs_end)
@@ -118,6 +123,21 @@ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry,
__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
}
+
+#include <linux/psci.h>
+
+static int enable_psci_bp_hardening(void *data)
+{
+ const struct arm64_cpu_capabilities *entry = data;
+
+ if (psci_ops.get_version)
+ install_bp_hardening_cb(entry,
+ (bp_hardening_cb_t)psci_ops.get_version,
+ __psci_hyp_bp_inval_start,
+ __psci_hyp_bp_inval_end);
+
+ return 0;
+}
#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */
#define MIDR_RANGE(model, min, max) \
@@ -261,6 +281,28 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
},
#endif
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+ .enable = enable_psci_bp_hardening,
+ },
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+ .enable = enable_psci_bp_hardening,
+ },
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+ .enable = enable_psci_bp_hardening,
+ },
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+ .enable = enable_psci_bp_hardening,
+ },
+#endif
{
}
};
--
2.1.4
^ permalink raw reply related
* [PATCH 12/14] iio: adc: at91-sama5d2_adc: support for position and pressure channels
From: Eugen Hristev @ 2018-01-04 15:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171229170236.06bf6394@archlinux>
On 29.12.2017 19:02, Jonathan Cameron wrote:
> On Fri, 22 Dec 2017 17:07:19 +0200
> Eugen Hristev <eugen.hristev@microchip.com> wrote:
>
>> The ADC IP supports position and pressure measurements for a touchpad
>> connected on channels 0,1,2,3 for a 4-wire touchscreen with pressure
>> measurement support.
>> Using the inkern API, a driver can request a trigger and read the
>> channel values from the ADC.
>> The implementation provides a trigger named "touch" which can be
>> connected to a consumer driver.
>> Once a driver connects and attaches a pollfunc to this trigger, the
>> configure trigger callback is called, and then the ADC driver will
>> initialize pad measurement.
>> First step is to enable touchscreen 4wire support and enable
>> pen detect IRQ.
>> Once a pen is detected, a periodic trigger is setup to trigger every
>> 2 ms (e.g.) and sample the resistive touchscreen values. The trigger poll
>> is called, and the consumer driver is then woke up, and it can read the
>> respective channels for the values : X, and Y for position and pressure
>> channel.
>> Because only one trigger can be active in hardware in the same time,
>> while touching the pad, the ADC will block any attempt to use the
>> triggered buffer. Same, conversions using the software trigger are also
>> impossible (since the periodic trigger is setup).
>> If some driver wants to attach while the trigger is in use, it will
>> also fail.
>> Once the pen is not detected anymore, the trigger is free for use (hardware
>> or software trigger, with or without DMA).
>> Channels 0,1,2 and 3 are unavailable if a touchscreen is enabled.
>>
>> Some parts of this patch are based on initial original work by
>> Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
>>
> OK, so comments inline.
>
> What I'm missing currently though is an explanation of why the slightly
> more standard arrangement of using a callback buffer doesn't work here.
> The only addition I think you need to do that is to allow a consumer to
> request a particular trigger. I also think some of the other provisions
> could be handled using standard features and slightly reducing the flexibility.
> I don't know for example if it's useful to allow other channels to be
> read when touch is not in progress or not.
>
> So restrictions:
>
> 1. Touch screen channels can only be read when touch is enabled.
> - use the available_scan_masks to control this. Or the callback that lets
> you do the same dynamically.
> 2. You need to push these channels to your consumer driver.
> - register a callback buffer rather than jumping through the hoops to
> insert your own pollfunc. That will call a function in your
> consumer, providing the data from the 3 channels directly.
> 3. You need to make sure it is using the right driver. For that you
> will I think need a new interface.
>
> Various other comments inline. I may well be missing something as this is
> a fair bit of complex code to read - if so then next version should have
> a clear cover letter describing why this more standard approach can't be
> used.
Hello Jonathan and thanks for the review of my patch series,
before starting and working over the required modifications and
suggestions that you sent me, I want to be a little more explicit about
the design of my implementation.
Hope this will clarify some things, and maybe I can as well understand
better what you have in mind to support this feature set.
Why have I picked a pollfunction: We discussed a while back on the
mailing list that you do not have an inkern mechanism to expose the
triggers to other drivers, and that it may be a good idea to have it for
such kind of actually multi function device, instead of having a MFD
driver, an ADC driver, and an Input driver, all sharing the same
register map, the same IRQ , etc, with some kind of synchronization to
avoid stepping on each other for the hardware resource.
So I considered to expose the trigger by attaching and detaching
pollfunctions to it. Which is the main thing what we use a trigger for.
So, what I had in mind, was to create a consumer driver that will
request triggers from the IIO device just like other drivers request
channels (part which is already done in IIO).
In order to do this I had to somehow wake up the consumer driver when
new data was available from the touchscreen. So, having the IRQ only in
the ADC device, and then on Pen detect and No pen detect just start or
stop the periodic trigger, which needs to be polled. The magic part is
that the consumer driver has a poll function already attached to this
trigger, so the poll function is just called every time we have new
data. The poll function is attached as an irq handler, and then we can
reuse all the read_raw data by using a scheduled work from the consumer
driver, to read the channels.
To do this, the ADC registers a special trigger named "touch trigger"
which is never enabled by the ADC driver. Instead, when a pollfunc is
attached to it, the attach function will also configure it with enabled
state. In the ADC, this means to start the touchscreen functionality. If
the touch is requested, it will standby and wait for pen detect IRQ.
Once we have pen detect, we can use a periodic trigger to sample the
touch data, and poll the "touch" trigger. The consumer driver will wake
up and schedule a work , that will use the standard read raw interface
(inkern) that will read three virtual channels (position + pressure).
They are not actual hardware channels, as the touch information is being
received on channels 0,1,2,3, but reading these virtual channels will
read from different registers inside the ADC IP ( x position, y
position, pressure), do some computations on the data, and feed the
consumer with the values , hiding the behind the scenes hardware
specific calculations.
After trigger is polled , the ADC will resume normal functionality, and
the consumer driver will continue to sleep.
We need to have a periodic trigger to sample the data because the actual
analog to digital conversion inside the IP block needs to be triggered.
The touchscreen data measurements cannot happen in hardware without
being triggered. If I try with a hrtimer to get a periodic IRQ to just
read the data, it will never be ready. The datasheet states that the
touchscreen measurements "will be attached to the conversion sequence".
So the periodic trigger is forcing a conversion sequence. This could be
done with a software trigger as well, but why the hassle to start it
every 2 milliseconds (or other time interval), if we can do it by
periodic trigger ?
Once we get the No pen IRQ, we stop the periodic trigger and it can be
used in another purpose (software or external as of now in the driver,
in the future we can add PWM trigger and Timer trigger)
In short, the ADC in Sama5D2 also supports touchscreen, and in
touchscreen mode , 4 of the channels are being used for this purpose.
This however, doesn't stop the ADC to use the other channels . The
hardware has 12 total single channels and they can be paired to have 6
more differential channels. The only thing that is blocked is the
trigger, but only if the pen is touching (when we start the periodic
trigger to sample the touchscreen). If the pen is not touching, an
external trigger or software trigger can be used without any issues (so
why limit the functionality, if this is available from hardware ?).
Because of the reason I discussed above (touchscreen sequence must be
triggered), we cannot use another trigger in the same time.
I see your idea with the callback buffer and it's worth exploring.
Mainly this series was to actually show you what I had in mind about
supporting the resistive touchscreen, and to give you some actually
working code/patch, so we can discuss based on real implementation, not
just suppositions.
You are right in many of the other comments that you said, and I will
come up with a v2 to this series. For now, I need to know if this is a
good or right direction in which I am going, or I should try to change
all the mechanism to callback buffer ? Or maybe I am totally in a bad
direction ?
The requirements are that the consumer driver needs to be somehow woke
up for every new touch data available, and report to the input
subsystem. As it was done before, the at91 old driver, just creates and
registers an input device by itself, and then reports the position and
touches. I was thinking that with this trigger consumer implementation,
things can be better in terms of subsystem separation and support.
Thanks again and let me know of your thoughts,
Eugen
[...]
^ permalink raw reply
* [linux-sunxi] [PATCH v4 0/2] Initial Allwinner V3s CSI Support
From: Ondřej Jirman @ 2018-01-04 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180104140625.5gbeaj5vgetusjlf@flea.lan>
On Thu, Jan 04, 2018 at 03:06:25PM +0100, Maxime Ripard wrote:
> On Mon, Dec 25, 2017 at 09:58:02AM +0100, Ond?ej Jirman wrote:
> > Hello,
> >
> > On Mon, Dec 25, 2017 at 11:15:26AM +0800, Yong wrote:
> > > Hi,
> > >
> > > On Fri, 22 Dec 2017 14:46:48 +0100
> > > Ond?ej Jirman <megous@megous.com> wrote:
> > >
> > > > Hello,
> > > >
> > > > Yong Deng p??e v P? 22. 12. 2017 v 17:32 +0800:
> > > > >
> > > > > Test input 0:
> > > > >
> > > > > Control ioctls:
> > > > > test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
> > > > > test VIDIOC_QUERYCTRL: OK (Not Supported)
> > > > > test VIDIOC_G/S_CTRL: OK (Not Supported)
> > > > > test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
> > > > > test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
> > > > > test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> > > > > Standard Controls: 0 Private Controls: 0
> > > >
> > > > I'm not sure if your driver passes control queries to the subdev. It
> > > > did not originally, and I'm not sure you picked up the change from my
> > > > version of the driver. "Not supported" here seems to indicate that it
> > > > does not.
> > > >
> > > > I'd be interested what's the recommended practice here. It sure helps
> > > > with some apps that expect to be able to modify various input controls
> > > > directly on the /dev/video# device. These are then supported out of the
> > > > box.
> > > >
> > > > It's a one-line change. See:
> > > >
> > > > https://www.kernel.org/doc/html/latest/media/kapi/v4l2-controls.html#in
> > > > heriting-controls
> > >
> > > I think this is a feature and not affect the driver's main function.
> > > I just focused on making the CSI main function to work properly in
> > > the initial version. Is this feature mandatory or most commonly used?
> >
> > I grepped the platform/ code and it seems, that inheriting controls
> > from subdevs is pretty common for input drivers. (there are varying
> > approaches though, some inherit by hand in the link function, some
> > just register and empty ctrl_handler on the v4l2_dev and leave the
> > rest to the core).
> >
> > Practically, I haven't found a common app that would allow me to enter
> > both /dev/video0 and /dev/v4l-subdevX. I'm sure anyone can write one
> > themselves, but it would be better if current controls were available
> > at the /dev/video0 device automatically.
> >
> > It's much simpler for the userspace apps than the alternative, which
> > is trying to identify the correct subdev that is currently
> > associated with the CSI driver at runtime, which is not exactly
> > straightforward and requires much more code, than a few lines in
> > the kernel, that are required to inherit controls:
>
> And it becomes much more complicated once you have the same controls
> on the v4l2 device and subdevice, which is not that uncommon.
Hi Maxime,
I don't think you understand the issue. In your hypothetical situation, if the
CSI device will have any controls in the future, the merging of controls from
subdev will be done automatically anyway, it's not some optional feature.
Also userspace will not get any more complicated than without my proposed change
to the driver. It will be at most the same as without the change if any subdev
controls are masked by the CSI device controls.
This CSI driver has no controls anyway. All my change does is create an empty
handler for future controls of the CSI driver, so that apps can depend on this
merging behavior right now, and not wait until someone adds the first control
to the CSI driver.
regards,
o.j.
>
> Maxime
>
>
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply
* [PATCH][v2] arm64: Allocate elfcorehdr & crashkernel mem before any reservation
From: Poonam Aggrwal @ 2018-01-04 15:34 UTC (permalink / raw)
To: linux-arm-kernel
Address for both crashkernel memory and elfcorehdr can be assigned
statically. For crashkernel memory it is via crashkernel=SIZE at ADDRESS
and elfcorehdr_addr via by kexec-utils in dump kernel device tree.
So memory should be reserved for both the above areas before any
other memory reservations are done. Otherwise overlaps may happen and
memory allocations will fail leading to failure in booting the
dump capture kernel.
Signed-off-by: Guanhua <guanhua.gao@nxp.com>
Signed-off-by: Poonam Aggrwal <poonam.aggrwal@nxp.com>
Signed-off-by: Abhimanyu Saini <abhimanyu.saini@nxp.com>
---
v2:
corrected the email address
reworked based on the discussions:(with Will Deacon and Takahiro)
https://patchwork.kernel.org/patch/10104249/
arch/arm64/mm/init.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 00e7b90..24ce15d 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -453,6 +453,14 @@ void __init arm64_memblock_init(void)
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
+
+ /* make these the first reservations to avoid chances of
+ * overlap
+ */
+ reserve_elfcorehdr();
+
+ reserve_crashkernel();
+
memblock_reserve(__pa_symbol(_text), _end - _text);
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) {
@@ -472,10 +480,6 @@ void __init arm64_memblock_init(void)
else
arm64_dma_phys_limit = PHYS_MASK + 1;
- reserve_crashkernel();
-
- reserve_elfcorehdr();
-
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
dma_contiguous_reserve(arm64_dma_phys_limit);
--
2.7.4
^ permalink raw reply related
* [PATCH v2 07/12] drm/sun4i: Add a driver for the display frontend
From: Chen-Yu Tsai @ 2018-01-04 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <78c17058b8a38a4e38005aec451dd22e9a329e05.1513609024.git-series.maxime.ripard@free-electrons.com>
On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The display frontend is an hardware block that can be used to implement
> some more advanced features like hardware scaling or colorspace
> conversions. It can also be used to implement the output format of the VPU.
>
> Let's create a minimal driver for it that will only enable the hardware
> scaling features.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/gpu/drm/sun4i/Makefile | 3 +-
> drivers/gpu/drm/sun4i/sun4i_drv.c | 16 +-
> drivers/gpu/drm/sun4i/sun4i_drv.h | 1 +-
> drivers/gpu/drm/sun4i/sun4i_frontend.c | 392 ++++++++++++++++++++++++++-
> drivers/gpu/drm/sun4i/sun4i_frontend.h | 96 ++++++-
> 5 files changed, 503 insertions(+), 5 deletions(-)
> create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.c
> create mode 100644 drivers/gpu/drm/sun4i/sun4i_frontend.h
>
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 0c2f8c7facae..b660d82011f4 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0
> sun4i-backend-y += sun4i_backend.o sun4i_layer.o
> +sun4i-frontend-y += sun4i_frontend.o
>
> sun4i-drm-y += sun4i_drv.o
> sun4i-drm-y += sun4i_framebuffer.o
> @@ -21,6 +22,6 @@ obj-$(CONFIG_DRM_SUN4I) += sun4i-tcon.o
> obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o
> obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
>
> -obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o sun4i-frontend.o
> obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
> obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 75c76cdd82bc..17bf9bfd98ba 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -98,6 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
> goto free_drm;
> }
> drm->dev_private = drv;
> + INIT_LIST_HEAD(&drv->frontend_list);
> INIT_LIST_HEAD(&drv->engine_list);
> INIT_LIST_HEAD(&drv->tcon_list);
>
> @@ -239,9 +240,11 @@ static int sun4i_drv_add_endpoints(struct device *dev,
> int count = 0;
>
> /*
> - * We don't support the frontend for now, so we will never
> - * have a device bound. Just skip over it, but we still want
> - * the rest our pipeline to be added.
> + * The frontend has been disabled in all of our old device
Not quite... I left them enabled in all the ones I did (A10/A20/A31)...
> + * trees. If we find a node that is the frontend and is
> + * disabled, we should just follow through and parse its
> + * child, but without adding it to the component list.
> + * Otherwise, we obviously want to add it to the list.
> */
> if (!sun4i_drv_node_is_frontend(node) &&
> !of_device_is_available(node))
> @@ -254,7 +257,12 @@ static int sun4i_drv_add_endpoints(struct device *dev,
> if (sun4i_drv_node_is_connector(node))
> return 0;
>
> - if (!sun4i_drv_node_is_frontend(node)) {
> + /*
> + * If the device is either just a regular device, or an
> + * enabled frontend, we add it to our component list.
> + */
> + if (!sun4i_drv_node_is_frontend(node) ||
> + (sun4i_drv_node_is_frontend(node) && of_device_is_available(node))) {
> /* Add current component */
> DRM_DEBUG_DRIVER("Adding component %pOF\n", node);
> drm_of_component_match_add(dev, match, compare_of, node);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index a960c89270cc..9c26a345f85c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -19,6 +19,7 @@
>
> struct sun4i_drv {
> struct list_head engine_list;
> + struct list_head frontend_list;
> struct list_head tcon_list;
>
> struct drm_fbdev_cma *fbdev;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> new file mode 100644
> index 000000000000..fb3e96ab57f7
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
> @@ -0,0 +1,392 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +#include <drm/drmP.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
> +
> +static const u32 sun4i_frontend_vert_coef[32] = {
> + 0x00004000, 0x000140ff, 0x00033ffe, 0x00043ffd,
> + 0x00063efc, 0xff083dfc, 0x000a3bfb, 0xff0d39fb,
> + 0xff0f37fb, 0xff1136fa, 0xfe1433fb, 0xfe1631fb,
> + 0xfd192ffb, 0xfd1c2cfb, 0xfd1f29fb, 0xfc2127fc,
> + 0xfc2424fc, 0xfc2721fc, 0xfb291ffd, 0xfb2c1cfd,
> + 0xfb2f19fd, 0xfb3116fe, 0xfb3314fe, 0xfa3611ff,
> + 0xfb370fff, 0xfb390dff, 0xfb3b0a00, 0xfc3d08ff,
> + 0xfc3e0600, 0xfd3f0400, 0xfe3f0300, 0xff400100,
> +};
> +
> +static const u32 sun4i_frontend_horz_coef[64] = {
> + 0x40000000, 0x00000000, 0x40fe0000, 0x0000ff03,
> + 0x3ffd0000, 0x0000ff05, 0x3ffc0000, 0x0000ff06,
> + 0x3efb0000, 0x0000ff08, 0x3dfb0000, 0x0000ff09,
> + 0x3bfa0000, 0x0000fe0d, 0x39fa0000, 0x0000fe0f,
> + 0x38fa0000, 0x0000fe10, 0x36fa0000, 0x0000fe12,
> + 0x33fa0000, 0x0000fd16, 0x31fa0000, 0x0000fd18,
> + 0x2ffa0000, 0x0000fd1a, 0x2cfa0000, 0x0000fc1e,
> + 0x29fa0000, 0x0000fc21, 0x27fb0000, 0x0000fb23,
> + 0x24fb0000, 0x0000fb26, 0x21fb0000, 0x0000fb29,
> + 0x1ffc0000, 0x0000fa2b, 0x1cfc0000, 0x0000fa2e,
> + 0x19fd0000, 0x0000fa30, 0x16fd0000, 0x0000fa33,
> + 0x14fd0000, 0x0000fa35, 0x11fe0000, 0x0000fa37,
> + 0x0ffe0000, 0x0000fa39, 0x0dfe0000, 0x0000fa3b,
> + 0x0afe0000, 0x0000fa3e, 0x08ff0000, 0x0000fb3e,
> + 0x06ff0000, 0x0000fb40, 0x05ff0000, 0x0000fc40,
> + 0x03ff0000, 0x0000fd41, 0x01ff0000, 0x0000fe42,
> +};
> +
> +static void sun4i_frontend_scaler_init(struct sun4i_frontend *frontend)
> +{
> + int i;
> +
> + for (i = 0; i < 32; i++) {
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i),
> + sun4i_frontend_horz_coef[2 * i]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i),
> + sun4i_frontend_horz_coef[2 * i]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i),
> + sun4i_frontend_horz_coef[2 * i + 1]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i),
> + sun4i_frontend_horz_coef[2 * i + 1]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTCOEF_REG(i),
> + sun4i_frontend_vert_coef[i]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTCOEF_REG(i),
> + sun4i_frontend_vert_coef[i]);
> + }
> +
> + regmap_update_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG, BIT(23), BIT(23));
> +}
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend)
> +{
> + return pm_runtime_get_sync(frontend->dev);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_init);
> +
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend)
> +{
> + pm_runtime_put(frontend->dev);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_exit);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> + struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + struct drm_gem_cma_object *gem;
> + dma_addr_t paddr;
> + int bpp;
> +
> + /* Get the physical address of the buffer in memory */
> + gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> + DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> + /* Set the line width */
> + DRM_DEBUG_DRIVER("Frontend stride: %d bytes\n", fb->pitches[0]);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_LINESTRD0_REG,
> + fb->pitches[0]);
> +
> + /* Compute the start of the displayed memory */
> + bpp = fb->format->cpp[0];
> + paddr = gem->paddr + fb->offsets[0];
> + paddr += (state->src_x >> 16) * bpp;
> + paddr += (state->src_y >> 16) * fb->pitches[0];
You can use drm_fb_cma_get_gem_addr(fb, state, 0), instead of open
coding it.
Do we need to convert the address, like with the backend?
> +
> + DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_BUF_ADDR0_REG, paddr);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_buffer);
> +
> +static int sun4i_frontend_drm_format_to_input_fmt(uint32_t fmt, u32 *val)
> +{
> + switch (fmt) {
> + case DRM_FORMAT_ARGB8888:
> + case DRM_FORMAT_XRGB8888:
> + *val = 3;
> + return 0;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int sun4i_frontend_drm_format_to_output_fmt(uint32_t fmt, u32 *val)
> +{
> + switch (fmt) {
> + case DRM_FORMAT_ARGB8888:
> + *val = 2;
> + return 0;
> +
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> + struct drm_plane *plane, uint32_t out_fmt)
> +{
> + struct drm_plane_state *state = plane->state;
> + struct drm_framebuffer *fb = state->fb;
> + u32 out_fmt_val;
> + u32 in_fmt_val;
> + int ret;
> +
> + ret = sun4i_frontend_drm_format_to_input_fmt(fb->format->format,
> + &in_fmt_val);
> + if (ret) {
> + DRM_DEBUG_DRIVER("Invalid input format\n");
> + return ret;
> + }
> +
> + ret = sun4i_frontend_drm_format_to_output_fmt(out_fmt, &out_fmt_val);
> + if (ret) {
> + DRM_DEBUG_DRIVER("Invalid output format\n");
> + return ret;
> + }
> +
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZPHASE_REG, 0x400);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZPHASE_REG, 0x400);
> +
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE0_REG, 0x400);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE0_REG, 0x400);
> +
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTPHASE1_REG, 0x400);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTPHASE1_REG, 0x400);
I really don't understand any of this. :(
> +
> + regmap_write(frontend->regs, SUN4I_FRONTEND_INPUT_FMT_REG,
> + SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(1) |
> + SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(5) |
> + SUN4I_FRONTEND_INPUT_FMT_PS(1));
> + regmap_write(frontend->regs, SUN4I_FRONTEND_OUTPUT_FMT_REG,
> + SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(1));
You don't seem to be using the values you got from the helper functions.
Moreover, they don't match the values you claim to support.
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_formats);
> +
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> + struct drm_plane *plane)
> +{
> + struct drm_plane_state *state = plane->state;
> +
> + /* Set height and width */
> + DRM_DEBUG_DRIVER("Frontend size W: %u H: %u\n",
> + state->crtc_w, state->crtc_h);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_INSIZE_REG,
> + SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> + state->src_w >> 16));
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_INSIZE_REG,
> + SUN4I_FRONTEND_INSIZE(state->src_h >> 16,
> + state->src_w >> 16));
Slighty off-topic, but does the kernel provide helpers for 16.16
fixed point arithmetic?
> +
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_OUTSIZE_REG,
> + SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_OUTSIZE_REG,
> + SUN4I_FRONTEND_OUTSIZE(state->crtc_h, state->crtc_w));
Do you need to set the line stride registers?
> +
> + DRM_DEBUG_DRIVER("Frontend horizontal scaling factor %d.%d\n", 1, 0);
Value doesn't match what is programmed.
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_HORZFACT_REG,
> + state->src_w / state->crtc_w);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_HORZFACT_REG,
> + state->src_w / state->crtc_w);
> +
> + DRM_DEBUG_DRIVER("Frontend vertical scaling factor %d.%d\n", 1, 0);
Neither does this.
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH0_VERTFACT_REG,
> + state->src_h / state->crtc_h);
> + regmap_write(frontend->regs, SUN4I_FRONTEND_CH1_VERTFACT_REG,
> + state->src_h / state->crtc_h);
I don't think you need to program any of the channel 1 registers for
interleaved data.
> +
> + regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> + SUN4I_FRONTEND_FRM_CTRL_REG_RDY,
> + SUN4I_FRONTEND_FRM_CTRL_REG_RDY);
> +}
> +EXPORT_SYMBOL(sun4i_frontend_update_coord);
> +
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend)
> +{
> + regmap_write_bits(frontend->regs, SUN4I_FRONTEND_FRM_CTRL_REG,
> + SUN4I_FRONTEND_FRM_CTRL_FRM_START,
> + SUN4I_FRONTEND_FRM_CTRL_FRM_START);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sun4i_frontend_enable);
> +
> +static struct regmap_config sun4i_frontend_regmap_config = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = 0x0a14,
> +};
> +
> +static int sun4i_frontend_bind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct sun4i_frontend *frontend;
> + struct drm_device *drm = data;
> + struct sun4i_drv *drv = drm->dev_private;
> + struct resource *res;
> + void __iomem *regs;
> +
> + frontend = devm_kzalloc(dev, sizeof(*frontend), GFP_KERNEL);
> + if (!frontend)
> + return -ENOMEM;
> +
> + dev_set_drvdata(dev, frontend);
> + frontend->dev = dev;
> + frontend->node = dev->of_node;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(regs))
> + return PTR_ERR(regs);
> +
> + frontend->regs = devm_regmap_init_mmio(dev, regs,
> + &sun4i_frontend_regmap_config);
> + if (IS_ERR(frontend->regs)) {
> + dev_err(dev, "Couldn't create the frontend regmap\n");
> + return PTR_ERR(frontend->regs);
> + }
> +
> + frontend->reset = devm_reset_control_get(dev, NULL);
> + if (IS_ERR(frontend->reset)) {
> + dev_err(dev, "Couldn't get our reset line\n");
> + return PTR_ERR(frontend->reset);
> + }
> +
> + frontend->bus_clk = devm_clk_get(dev, "ahb");
> + if (IS_ERR(frontend->bus_clk)) {
> + dev_err(dev, "Couldn't get our bus clock\n");
> + return PTR_ERR(frontend->bus_clk);
> + }
> +
> + frontend->mod_clk = devm_clk_get(dev, "mod");
> + if (IS_ERR(frontend->mod_clk)) {
> + dev_err(dev, "Couldn't get our mod clock\n");
> + return PTR_ERR(frontend->mod_clk);
> + }
> +
> + frontend->ram_clk = devm_clk_get(dev, "ram");
> + if (IS_ERR(frontend->ram_clk)) {
> + dev_err(dev, "Couldn't get our ram clock\n");
> + return PTR_ERR(frontend->ram_clk);
> + }
> +
> + list_add_tail(&frontend->list, &drv->frontend_list);
Maybe force a reset here?
> + pm_runtime_enable(dev);
> +
> + return 0;
> +}
> +
> +static void sun4i_frontend_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> + list_del(&frontend->list);
> + pm_runtime_force_suspend(dev);
> +}
> +
> +static const struct component_ops sun4i_frontend_ops = {
> + .bind = sun4i_frontend_bind,
> + .unbind = sun4i_frontend_unbind,
> +};
> +
> +static int sun4i_frontend_probe(struct platform_device *pdev)
> +{
> + return component_add(&pdev->dev, &sun4i_frontend_ops);
> +}
> +
> +static int sun4i_frontend_remove(struct platform_device *pdev)
> +{
> + component_del(&pdev->dev, &sun4i_frontend_ops);
> +
> + return 0;
> +}
> +
> +static int sun4i_frontend_runtime_resume(struct device *dev)
> +{
> + struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = reset_control_deassert(frontend->reset);
> + if (ret) {
> + dev_err(dev, "Couldn't deassert our reset line\n");
> + return ret;
> + }
> +
> + clk_set_rate(frontend->mod_clk, 300000000);
> +
> + clk_prepare_enable(frontend->bus_clk);
> + clk_prepare_enable(frontend->mod_clk);
> + clk_prepare_enable(frontend->ram_clk);
I wonder if the clocks should be enabled first, so the registers
and internal state gets properly reset?
> +
> + regmap_update_bits(frontend->regs, SUN4I_FRONTEND_EN_REG,
> + SUN4I_FRONTEND_EN_EN,
> + SUN4I_FRONTEND_EN_EN);
> +
You also need to set OUT_PORT_SEL in FRM_CTRL_REG so that frontend1
correctly outputs to backend1, assuming a static mapping.
> + regmap_update_bits(frontend->regs, SUN4I_FRONTEND_BYPASS_REG,
> + SUN4I_FRONTEND_BYPASS_CSC_EN,
> + SUN4I_FRONTEND_BYPASS_CSC_EN);
> +
> + sun4i_frontend_scaler_init(frontend);
> +
> + return 0;
> +}
> +
> +static int sun4i_frontend_runtime_suspend(struct device *dev)
> +{
> + struct sun4i_frontend *frontend = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(frontend->ram_clk);
> + clk_disable_unprepare(frontend->mod_clk);
> + clk_disable_unprepare(frontend->bus_clk);
> +
> + reset_control_assert(frontend->reset);
> +
> + return 0;
> +}
> +
> +static const struct dev_pm_ops sun4i_frontend_pm_ops = {
> + .runtime_resume = sun4i_frontend_runtime_resume,
> + .runtime_suspend = sun4i_frontend_runtime_suspend,
> +};
> +
> +static const struct of_device_id sun4i_frontend_of_table[] = {
> + { .compatible = "allwinner,sun5i-a13-display-frontend" },
> + { .compatible = "allwinner,sun6i-a31-display-frontend" },
What about A10 and A20?
Regards
ChenYu
> + { .compatible = "allwinner,sun8i-a33-display-frontend" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, sun4i_frontend_of_table);
> +
> +static struct platform_driver sun4i_frontend_driver = {
> + .probe = sun4i_frontend_probe,
> + .remove = sun4i_frontend_remove,
> + .driver = {
> + .name = "sun4i-frontend",
> + .of_match_table = sun4i_frontend_of_table,
> + .pm = &sun4i_frontend_pm_ops,
> + },
> +};
> +module_platform_driver(sun4i_frontend_driver);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Allwinner A10 Display Engine Frontend Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.h b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> new file mode 100644
> index 000000000000..5adc2c7266bc
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_frontend.h
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2017 Free Electrons
> + * Maxime Ripard <maxime.ripard@free-electrons.com>
> + */
> +
> +#ifndef _SUN4I_FRONTEND_H_
> +#define _SUN4I_FRONTEND_H_
> +
> +#include <linux/list.h>
> +
> +#define SUN4I_FRONTEND_EN_REG 0x000
> +#define SUN4I_FRONTEND_EN_EN BIT(0)
> +
> +#define SUN4I_FRONTEND_FRM_CTRL_REG 0x004
> +#define SUN4I_FRONTEND_FRM_CTRL_FRM_START BIT(16)
> +#define SUN4I_FRONTEND_FRM_CTRL_COEF_RDY BIT(1)
> +#define SUN4I_FRONTEND_FRM_CTRL_REG_RDY BIT(0)
> +
> +#define SUN4I_FRONTEND_BYPASS_REG 0x008
> +#define SUN4I_FRONTEND_BYPASS_CSC_EN BIT(1)
> +
> +#define SUN4I_FRONTEND_BUF_ADDR0_REG 0x020
> +
> +#define SUN4I_FRONTEND_LINESTRD0_REG 0x040
> +
> +#define SUN4I_FRONTEND_INPUT_FMT_REG 0x04c
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_MOD(mod) ((mod) << 8)
> +#define SUN4I_FRONTEND_INPUT_FMT_DATA_FMT(fmt) ((fmt) << 4)
> +#define SUN4I_FRONTEND_INPUT_FMT_PS(ps) (ps)
> +
> +#define SUN4I_FRONTEND_OUTPUT_FMT_REG 0x05c
> +#define SUN4I_FRONTEND_OUTPUT_FMT_DATA_FMT(fmt) (fmt)
> +
> +#define SUN4I_FRONTEND_CH0_INSIZE_REG 0x100
> +#define SUN4I_FRONTEND_INSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_OUTSIZE_REG 0x104
> +#define SUN4I_FRONTEND_OUTSIZE(h, w) ((((h) - 1) << 16) | (((w) - 1)))
> +
> +#define SUN4I_FRONTEND_CH0_HORZFACT_REG 0x108
> +#define SUN4I_FRONTEND_HORZFACT(i, f) (((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_VERTFACT_REG 0x10c
> +#define SUN4I_FRONTEND_VERTFACT(i, f) (((i) << 16) | (f))
> +
> +#define SUN4I_FRONTEND_CH0_HORZPHASE_REG 0x110
> +#define SUN4I_FRONTEND_CH0_VERTPHASE0_REG 0x114
> +#define SUN4I_FRONTEND_CH0_VERTPHASE1_REG 0x118
> +
> +#define SUN4I_FRONTEND_CH1_INSIZE_REG 0x200
> +#define SUN4I_FRONTEND_CH1_OUTSIZE_REG 0x204
> +#define SUN4I_FRONTEND_CH1_HORZFACT_REG 0x208
> +#define SUN4I_FRONTEND_CH1_VERTFACT_REG 0x20c
> +
> +#define SUN4I_FRONTEND_CH1_HORZPHASE_REG 0x210
> +#define SUN4I_FRONTEND_CH1_VERTPHASE0_REG 0x214
> +#define SUN4I_FRONTEND_CH1_VERTPHASE1_REG 0x218
> +
> +#define SUN4I_FRONTEND_CH0_HORZCOEF0_REG(i) (0x400 + i * 4)
> +#define SUN4I_FRONTEND_CH0_HORZCOEF1_REG(i) (0x480 + i * 4)
> +#define SUN4I_FRONTEND_CH0_VERTCOEF_REG(i) (0x500 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF0_REG(i) (0x600 + i * 4)
> +#define SUN4I_FRONTEND_CH1_HORZCOEF1_REG(i) (0x680 + i * 4)
> +#define SUN4I_FRONTEND_CH1_VERTCOEF_REG(i) (0x700 + i * 4)
> +
> +struct clk;
> +struct device_node;
> +struct drm_plane;
> +struct regmap;
> +struct reset_control;
> +
> +struct sun4i_frontend {
> + struct list_head list;
> + struct device *dev;
> + struct device_node *node;
> +
> + struct clk *bus_clk;
> + struct clk *mod_clk;
> + struct clk *ram_clk;
> + struct regmap *regs;
> + struct reset_control *reset;
> +};
> +
> +int sun4i_frontend_init(struct sun4i_frontend *frontend);
> +void sun4i_frontend_exit(struct sun4i_frontend *frontend);
> +int sun4i_frontend_enable(struct sun4i_frontend *frontend);
> +
> +void sun4i_frontend_update_buffer(struct sun4i_frontend *frontend,
> + struct drm_plane *plane);
> +void sun4i_frontend_update_coord(struct sun4i_frontend *frontend,
> + struct drm_plane *plane);
> +int sun4i_frontend_update_formats(struct sun4i_frontend *frontend,
> + struct drm_plane *plane, uint32_t out_fmt);
> +
> +#endif /* _SUN4I_FRONTEND_H_ */
> --
> git-series 0.9.1
^ permalink raw reply
* [PATCH] ARM: imx_v6_v7_defconfig: select the CONFIG_CPUFREQ_DT
From: Anson Huang @ 2018-01-04 15:36 UTC (permalink / raw)
To: linux-arm-kernel
Select CONFIG_CPUFREQ_DT by default to enable
cpu-freq driver for i.MX7D.
The rest changes are generated by "make savedefconfig".
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
arch/arm/configs/imx_v6_v7_defconfig | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 0d44949..d4c8f35 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -48,9 +48,7 @@ CONFIG_PCI_IMX6=y
CONFIG_SMP=y
CONFIG_ARM_PSCI=y
CONFIG_PREEMPT_VOLUNTARY=y
-CONFIG_AEABI=y
CONFIG_HIGHMEM=y
-CONFIG_CMA=y
CONFIG_FORCE_MAX_ZONEORDER=14
CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
CONFIG_KEXEC=y
@@ -59,6 +57,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPUFREQ_DT=y
CONFIG_ARM_IMX6Q_CPUFREQ=y
CONFIG_CPU_IDLE=y
CONFIG_VFP=y
@@ -81,7 +80,6 @@ CONFIG_CAN_FLEXCAN=y
CONFIG_BT=y
CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_LL=y
CONFIG_CFG80211=y
CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=y
@@ -90,7 +88,6 @@ CONFIG_RFKILL_INPUT=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
-CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_IMX_WEIM=y
CONFIG_CONNECTOR=y
@@ -167,9 +164,9 @@ CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_TOUCHSCREEN_EGALAX=y
+CONFIG_TOUCHSCREEN_MAX11801=y
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
CONFIG_TOUCHSCREEN_EDT_FT5X06=y
-CONFIG_TOUCHSCREEN_MAX11801=y
CONFIG_TOUCHSCREEN_MC13783=y
CONFIG_TOUCHSCREEN_TSC2004=y
CONFIG_TOUCHSCREEN_TSC2007=y
@@ -178,7 +175,6 @@ CONFIG_TOUCHSCREEN_SX8654=y
CONFIG_TOUCHSCREEN_COLIBRI_VF50=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MMA8450=y
-CONFIG_HID_MULTITOUCH=y
CONFIG_SERIO_SERPORT=m
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_IMX=y
@@ -210,7 +206,6 @@ CONFIG_POWER_RESET_SYSCON_POWEROFF=y
CONFIG_POWER_SUPPLY=y
CONFIG_SENSORS_GPIO_FAN=y
CONFIG_SENSORS_IIO_HWMON=y
-CONFIG_THERMAL=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_CPU_THERMAL=y
CONFIG_IMX_THERMAL=y
@@ -228,13 +223,13 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MC13783=y
CONFIG_REGULATOR_MC13892=y
CONFIG_REGULATOR_PFUZE100=y
+CONFIG_RC_CORE=y
+CONFIG_RC_DEVICES=y
+CONFIG_IR_GPIO_CIR=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_RC_CORE=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
-CONFIG_RC_DEVICES=y
-CONFIG_IR_GPIO_CIR=y
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m
CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -245,7 +240,6 @@ CONFIG_VIDEO_CODA=m
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
CONFIG_VIDEO_ADV7180=m
CONFIG_VIDEO_OV5640=m
-CONFIG_SOC_CAMERA_OV2640=y
CONFIG_IMX_IPUV3_CORE=y
CONFIG_DRM=y
CONFIG_DRM_PANEL_SIMPLE=y
@@ -283,6 +277,7 @@ CONFIG_SND_SOC_CS42XX8_I2C=y
CONFIG_SND_SOC_TLV320AIC3X=y
CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SIMPLE_CARD=y
+CONFIG_HID_MULTITOUCH=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MXC=y
--
1.9.1
^ permalink raw reply related
* [PATCH 02/11] arm64: Kconfig: Reword UNMAP_KERNEL_AT_EL0 kconfig entry
From: Christoph Hellwig @ 2018-01-04 15:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515078515-13723-3-git-send-email-will.deacon@arm.com>
On Thu, Jan 04, 2018 at 03:08:26PM +0000, Will Deacon wrote:
> Although CONFIG_UNMAP_KERNEL_AT_EL0 does make KASLR more robust, it's
> actually more useful as a mitigation against speculation attacks that
> can leak arbitrary kernel data to userspace through speculation.
>
> Reword the Kconfig help message to reflect this, and make the option
> depend on EXPERT so that it is on by default for the majority of users.
>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
Why is this not reusing the PAGE_TABLE_ISOLATION setting in
security/Kconfig ?
^ permalink raw reply
* [PATCH 3/3] [v6] pinctrl: qcom: qdf2xxx: add support for new ACPI HID QCOM8002
From: Timur Tabi @ 2018-01-04 15:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171222014633.GD7997@codeaurora.org>
On 12/21/2017 07:46 PM, Stephen Boyd wrote:
> Ok. That's testable with acpi_match_device_ids() though. I can
> add that into pinctrl-msm.c so we don't have to pass info about
> available gpios from ACPI specific driver into the pinctrl-msm
> core driver. That's why I'm trying to avoid doing it in the ACPI
> specific driver. Do it close to where the gpiochip is created
> instead.
I guess we're just going to have to agree to disagree. I see the DSDs
as being SOC-specific, and therefore belong in the SOC driver. I'm
still going to need an SOC driver to define the TLMM register layout.
But as I said earlier, I've already spent way too much time working on a
driver that, in all likelihood, never be used in any production system
anyway.
I look forward to reviewing the next version of your patch.
> Maybe future HIDs could follow the DT design and then we can look
> for the same device property name in both firmwares.
DSDs generally don't have the vendor prefix that DT properties do.
> Parsing
> ranges is simpler.
I'm not sure I agree with that.
--
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.
^ permalink raw reply
* [PATCH v2 08/12] drm/sun4i: backend: Wire in the frontend
From: Chen-Yu Tsai @ 2018-01-04 15:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9e8c0ce7192dc9ec59da6906e8f6e8f282ac3809.1513609024.git-series.maxime.ripard@free-electrons.com>
On Mon, Dec 18, 2017 at 10:57 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Now that we have a driver, we can make use of it. This is done by
> adding a flag to our custom plane state that will trigger whether we should
> use the frontend on that particular plane or not.
>
> The rest is just plumbing to set up the backend to not perform the DMA but
> receive its data from the frontend.
>
> Note that we're still not making any use of the frontend itself, as no one
> is setting the flag yet.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
> drivers/gpu/drm/sun4i/sun4i_backend.c | 90 ++++++++++++++++++++++++++++-
> drivers/gpu/drm/sun4i/sun4i_backend.h | 8 ++-
> drivers/gpu/drm/sun4i/sun4i_crtc.c | 1 +-
> drivers/gpu/drm/sun4i/sun4i_layer.c | 33 +++++++++-
> drivers/gpu/drm/sun4i/sun4i_layer.h | 1 +-
> 5 files changed, 130 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index f971d3fb5ee4..29e1ca7e01fe 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -26,6 +26,7 @@
>
> #include "sun4i_backend.h"
> #include "sun4i_drv.h"
> +#include "sun4i_frontend.h"
> #include "sun4i_layer.h"
> #include "sunxi_engine.h"
>
> @@ -203,6 +204,30 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
> return 0;
> }
>
> +int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
> + int layer, uint32_t fmt)
> +{
> + u32 val;
> + int ret;
> +
> + ret = sun4i_backend_drm_format_to_layer(NULL, fmt, &val);
> + if (ret) {
> + DRM_DEBUG_DRIVER("Invalid format\n");
> + return ret;
> + }
> +
> + regmap_update_bits(backend->engine.regs,
> + SUN4I_BACKEND_ATTCTL_REG0(layer),
> + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
> + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
You also need to select which frontend to use by setting LAY_VDOSEL.
> +
> + regmap_update_bits(backend->engine.regs,
> + SUN4I_BACKEND_ATTCTL_REG1(layer),
> + SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> + return 0;
> +}
> +
> int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
> int layer, struct drm_plane *plane)
> {
> @@ -246,6 +271,36 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
> return 0;
> }
>
> +static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
> +{
> + struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
> + struct sun4i_frontend *frontend = backend->frontend;
> +
> + if (!frontend)
> + return;
> +
> + /*
> + * In a teardown scenario with the frontend involved, we have
> + * to keep the frontend enabled until the next vblank, and
> + * only then disable it.
> + *
> + * This is due to the fact that the backend will not take into
> + * account the new configuration (with the plane that used to
> + * be fed by the frontend now disabled) until we write to the
> + * commit bit and the hardware fetches the new configuration
> + * during the next vblank.
> + *
> + * So we keep the frontend around in order to prevent any
> + * visual artifacts.
> + */
> + spin_lock(&backend->frontend_lock);
> + if (backend->frontend_teardown) {
> + sun4i_frontend_exit(frontend);
> + backend->frontend_teardown = false;
> + }
> + spin_unlock(&backend->frontend_lock);
> +};
> +
> static int sun4i_backend_init_sat(struct device *dev) {
> struct sun4i_backend *backend = dev_get_drvdata(dev);
> int ret;
> @@ -330,11 +385,40 @@ static int sun4i_backend_of_get_id(struct device_node *node)
> return ret;
> }
>
> +static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
> + struct device_node *node)
> +{
> + struct device_node *port, *ep, *remote;
> + struct sun4i_frontend *frontend;
> +
> + port = of_graph_get_port_by_id(node, 0);
> + if (!port)
> + return ERR_PTR(-EINVAL);
> +
> + for_each_available_child_of_node(port, ep) {
> + remote = of_graph_get_remote_port_parent(ep);
> + if (!remote)
> + continue;
> +
> + /* does this node match any registered engines? */
> + list_for_each_entry(frontend, &drv->frontend_list, list) {
> + if (remote == frontend->node) {
> + of_node_put(remote);
> + of_node_put(port);
> + return frontend;
This would return the same frontend for both backends in a dual pipeline setup.
Remember that we now have cross-connecting links between frontends and backends
of both pipelines.
Instead just match the frontend's ID to the backend's ID. BTW I think you left
out the ID thing in the frontend driver.
The rest looks good.
ChenYu
^ permalink raw reply
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