* [kernel-hardening][PATCH v2 0/3] arm: Makes ptdump resuable and add WX page checking
From: Jinbum Park @ 2017-12-01 11:32 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Page table dumping code for arm64-x86 is reusable,
and they have function for WX page checking.
But arm doesn't have that.
This path series are to makes ptdump reusable,
and add WX page checking for arm.
This is heavily based on arm64 version.
v2 :
Fix a sender name of mail header, there was an mistake.
(from "jinb.park" to Jinbum Park)
Contents of patch-set are perfectly same.
Jinbum Park (3):
arm: mm: dump: make page table dumping reusable
arm: mm: dump: make the page table dumping seq_file optional
arm: mm: dump: add checking for writable and executable pages
arch/arm/Kconfig.debug | 33 +++++++-
arch/arm/include/asm/ptdump.h | 56 ++++++++++++++
arch/arm/mm/Makefile | 3 +-
arch/arm/mm/dump.c | 171 +++++++++++++++++++++++++++++++-----------
arch/arm/mm/init.c | 2 +
arch/arm/mm/ptdump_debugfs.c | 34 +++++++++
6 files changed, 253 insertions(+), 46 deletions(-)
create mode 100644 arch/arm/include/asm/ptdump.h
create mode 100644 arch/arm/mm/ptdump_debugfs.c
--
1.9.1
^ permalink raw reply
* [PATCH 6/6] arm64: dts: marvell: armada-37xx: add nodes allowing cpufreq support
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
In order to be able to use cpu freq, we need to associate a clock to each
CPU and to expose the power management registers.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm64/boot/dts/marvell/armada-372x.dtsi | 1 +
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 7 +++++++
2 files changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/marvell/armada-372x.dtsi b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
index 59d7557d3b1b..2554e0baea6b 100644
--- a/arch/arm64/boot/dts/marvell/armada-372x.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-372x.dtsi
@@ -56,6 +56,7 @@
device_type = "cpu";
compatible = "arm,cortex-a53","arm,armv8";
reg = <0x1>;
+ clocks = <&nb_periph_clk 16>;
enable-method = "psci";
};
};
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 90c26d616a54..6e51ed54d75c 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -65,6 +65,7 @@
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0>;
+ clocks = <&nb_periph_clk 16>;
enable-method = "psci";
};
};
@@ -234,6 +235,12 @@
};
};
+ nb_pm: nb_pm at 14000 {
+ compatible = "marvell,armada-3700-nb-pm",
+ "syscon";
+ reg = <0x14000 0x60>;
+ };
+
pinctrl_sb: pinctrl at 18800 {
compatible = "marvell,armada3710-sb-pinctrl",
"syscon", "simple-mfd";
--
2.15.0
^ permalink raw reply related
* [PATCH 5/6] cpufreq: Add DVFS support for Armada 37xx
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
This patch adds DVFS support for the Armada 37xx SoCs
There are up to four CPU frequency loads for Armada 37xx controlled by
the hardware.
This driver associates the CPU load level to a frequency, then the
hardware will switch while selecting a load level.
The hardware also can associate a voltage for each level (AVS support)
but it is not yet supported
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/Kconfig.arm | 7 +
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/armada-37xx-cpufreq.c | 241 ++++++++++++++++++++++++++++++++++
3 files changed, 249 insertions(+)
create mode 100644 drivers/cpufreq/armada-37xx-cpufreq.c
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 17625115c67f..3018ff0d068f 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -19,6 +19,13 @@ config ACPI_CPPC_CPUFREQ
If in doubt, say N.
+config ARM_ARMADA_37XX_CPUFREQ
+ tristate "Armada 37xx CPUFreq support"
+ depends on ARCH_MVEBU
+ help
+ This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
+ The Armada 37xx PMU supports 4 frequency and VDD levels.
+
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index d762e76887e7..e07715ce8844 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
# LITTLE drivers, so that it is probed last.
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
+obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c
new file mode 100644
index 000000000000..40c9a744cc6e
--- /dev/null
+++ b/drivers/cpufreq/armada-37xx-cpufreq.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CPU frequency scaling support for Armada 37xx platform.
+ *
+ * Copyright (C) 2017 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* Power management in North Bridge register set */
+#define ARMADA_37XX_NB_L0L1 0x18
+#define ARMADA_37XX_NB_L2L3 0x1C
+#define ARMADA_37XX_NB_TBG_DIV_OFF 13
+#define ARMADA_37XX_NB_TBG_DIV_MASK 0x7
+#define ARMADA_37XX_NB_CLK_SEL_OFF 11
+#define ARMADA_37XX_NB_CLK_SEL_MASK 0x1
+#define ARMADA_37XX_NB_CLK_SEL_TBG 0x1
+#define ARMADA_37XX_NB_TBG_SEL_OFF 9
+#define ARMADA_37XX_NB_TBG_SEL_MASK 0x3
+#define ARMADA_37XX_NB_VDD_SEL_OFF 6
+#define ARMADA_37XX_NB_VDD_SEL_MASK 0x3
+#define ARMADA_37XX_NB_CONFIG_SHIFT 16
+#define ARMADA_37XX_NB_DYN_MOD 0x24
+#define ARMADA_37XX_NB_CLK_SEL_EN BIT(26)
+#define ARMADA_37XX_NB_TBG_EN BIT(28)
+#define ARMADA_37XX_NB_DIV_EN BIT(29)
+#define ARMADA_37XX_NB_VDD_EN BIT(30)
+#define ARMADA_37XX_NB_DFS_EN BIT(31)
+#define ARMADA_37XX_NB_CPU_LOAD 0x30
+#define ARMADA_37XX_NB_CPU_LOAD_MASK 0x3
+#define ARMADA_37XX_DVFS_LOAD_0 0
+#define ARMADA_37XX_DVFS_LOAD_1 1
+#define ARMADA_37XX_DVFS_LOAD_2 2
+#define ARMADA_37XX_DVFS_LOAD_3 3
+
+/*
+ * On Armada 37xx the Power management manages 4 level of CPU load,
+ * each level can be associated with a CPU clock source, a CPU
+ * divider, a VDD level, etc...
+ */
+#define LOAD_LEVEL_NR 4
+
+struct armada_37xx_dvfs {
+ u32 cpu_freq_max;
+ u8 divider[LOAD_LEVEL_NR];
+};
+
+static struct armada_37xx_dvfs armada_37xx_dvfs[] = {
+ {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} },
+ {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} },
+ {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} },
+ {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} },
+};
+
+static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(armada_37xx_dvfs); i++) {
+ if (freq == armada_37xx_dvfs[i].cpu_freq_max)
+ return &armada_37xx_dvfs[i];
+ }
+
+ pr_err("Unsupported CPU frequency %d MHz\n", freq/1000000);
+ return NULL;
+}
+
+/*
+ * Setup the four level managed by the hardware. Once the four level
+ * will be configured then the DVFS will be enabled.
+ */
+static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
+ struct clk *clk, u8 *divider)
+{
+ int load_level;
+ struct clk *parent;
+
+ for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
+ unsigned int reg, mask, val, offset = 0;
+
+ if (load_level <= ARMADA_37XX_DVFS_LOAD_1)
+ reg = ARMADA_37XX_NB_L0L1;
+ else
+ reg = ARMADA_37XX_NB_L2L3;
+
+ if (load_level == ARMADA_37XX_DVFS_LOAD_0 ||
+ load_level == ARMADA_37XX_DVFS_LOAD_2)
+ offset += ARMADA_37XX_NB_CONFIG_SHIFT;
+
+ /* Set cpu clock source, for all the level we use TBG */
+ val = ARMADA_37XX_NB_CLK_SEL_TBG << ARMADA_37XX_NB_CLK_SEL_OFF;
+ mask = (ARMADA_37XX_NB_CLK_SEL_MASK
+ << ARMADA_37XX_NB_CLK_SEL_OFF);
+
+ /*
+ * Set cpu divider based on the pre-computed array in
+ * order to have balanced step.
+ */
+ val |= divider[load_level] << ARMADA_37XX_NB_TBG_DIV_OFF;
+ mask |= (ARMADA_37XX_NB_TBG_DIV_MASK
+ << ARMADA_37XX_NB_TBG_DIV_OFF);
+
+ /* Set VDD divider which is actually the load level. */
+ val |= load_level << ARMADA_37XX_NB_VDD_SEL_OFF;
+ mask |= (ARMADA_37XX_NB_VDD_SEL_MASK
+ << ARMADA_37XX_NB_VDD_SEL_OFF);
+
+ val <<= offset;
+ mask <<= offset;
+
+ regmap_update_bits(base, reg, mask, val);
+ }
+
+ /*
+ * Set cpu clock source, for all the level we keep the same
+ * clock source that the one already configured. For this one
+ * we need to use the clock framework
+ */
+ parent = clk_get_parent(clk);
+ clk_set_parent(clk, parent);
+}
+
+static void __init armada37xx_cpufreq_disable_dvfs(struct regmap *base)
+{
+ unsigned int reg = ARMADA_37XX_NB_DYN_MOD,
+ mask = ARMADA_37XX_NB_DFS_EN;
+
+ regmap_update_bits(base, reg, mask, 0);
+}
+
+static void __init armada37xx_cpufreq_enable_dvfs(struct regmap *base)
+{
+ unsigned int val, reg = ARMADA_37XX_NB_CPU_LOAD,
+ mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
+
+ /* Start with the highest load (0) */
+ val = ARMADA_37XX_DVFS_LOAD_0;
+ regmap_update_bits(base, reg, mask, val);
+
+ /* Now enable DVFS for the CPUs */
+ reg = ARMADA_37XX_NB_DYN_MOD;
+ mask = ARMADA_37XX_NB_CLK_SEL_EN | ARMADA_37XX_NB_TBG_EN |
+ ARMADA_37XX_NB_DIV_EN | ARMADA_37XX_NB_VDD_EN |
+ ARMADA_37XX_NB_DFS_EN;
+
+ regmap_update_bits(base, reg, mask, mask);
+}
+
+static int __init armada37xx_cpufreq_driver_init(void)
+{
+ struct armada_37xx_dvfs *dvfs;
+ struct platform_device *pdev;
+ unsigned int cur_frequency;
+ struct regmap *nb_pm_base;
+ struct device *cpu_dev;
+ int load_level, ret;
+ struct clk *clk;
+
+ nb_pm_base =
+ syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
+
+ if (IS_ERR(nb_pm_base))
+ return -ENODEV;
+
+ /* Before doing any configuration on the DVFS first, disable it */
+ armada37xx_cpufreq_disable_dvfs(nb_pm_base);
+
+ /*
+ * On CPU 0 register the operating points supported (which are
+ * the nominal CPU frequency and full integer divisions of
+ * it).
+ */
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ dev_err(cpu_dev, "Cannot get CPU\n");
+ return -ENODEV;
+ }
+
+ clk = clk_get(cpu_dev, 0);
+ if (IS_ERR(clk)) {
+ dev_err(cpu_dev, "Cannot get clock for CPU0\n");
+ return PTR_ERR(clk);
+ }
+
+ /* Get nominal (current) CPU frequency */
+ cur_frequency = clk_get_rate(clk);
+ if (!cur_frequency) {
+ dev_err(cpu_dev, "Failed to get clock rate for CPU\n");
+ return -EINVAL;
+ }
+
+ dvfs = armada_37xx_cpu_freq_info_get(cur_frequency);
+ if (!dvfs)
+ return -EINVAL;
+
+ armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider);
+
+ /*
+ * In case of a failure of dev_pm_opp_add(), we don't bother
+ * with cleaning up the registered OPP (there's no function to
+ * do so), and simply cancel the registration of the cpufreq
+ * device.
+ */
+ for (load_level = ARMADA_37XX_DVFS_LOAD_0; load_level < LOAD_LEVEL_NR;
+ load_level++) {
+ unsigned long freq = dvfs->divider[load_level];
+
+ ret = dev_pm_opp_add(cpu_dev, freq, 0);
+ if (ret)
+ return ret;
+ }
+
+ /* Now that everything is setup, enable the DVFS at hardware level */
+ armada37xx_cpufreq_enable_dvfs(nb_pm_base);
+
+ pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+
+ return PTR_ERR_OR_ZERO(pdev);
+}
+/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
+late_initcall(armada37xx_cpufreq_driver_init);
+
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 37xx cpufreq driver");
+MODULE_LICENSE("GPL");
--
2.15.0
^ permalink raw reply related
* [PATCH 4/6] MAINTAINERS: add new entries for Armada 37xx cpufreq driver
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
This new driver belongs to the mvebu family, update the MAINTAINER file
to document it.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index aa71ab52fd76..98dcee849481 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1582,6 +1582,7 @@ F: arch/arm/boot/dts/kirkwood*
F: arch/arm/configs/mvebu_*_defconfig
F: arch/arm/mach-mvebu/
F: arch/arm64/boot/dts/marvell/armada*
+F: drivers/cpufreq/armada-37xx-cpufreq.c
F: drivers/cpufreq/mvebu-cpufreq.c
F: drivers/irqchip/irq-armada-370-xp.c
F: drivers/irqchip/irq-mvebu-*
--
2.15.0
^ permalink raw reply related
* [PATCH 3/6] cpufreq: sort the drivers in ARM part
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
Keep the driver files alphabetically sorted.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/Makefile | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 812f9e0d01a3..d762e76887e7 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -53,22 +53,24 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
+obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o
+obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
-obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o
-obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o
obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
obj-$(CONFIG_ARM_S3C2440_CPUFREQ) += s3c2440-cpufreq.o
obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
+obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o
+obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
@@ -81,8 +83,6 @@ obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o
obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
-obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o
-obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
##################################################################################
--
2.15.0
^ permalink raw reply related
* [PATCH 2/6] cpufreq: ARM: sort the Kconfig menu
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
Group all the related big LITTLE configuration together and sort the
other entries in alphabetic order.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
drivers/cpufreq/Kconfig.arm | 82 ++++++++++++++++++++++-----------------------
1 file changed, 41 insertions(+), 41 deletions(-)
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index bdce4488ded1..17625115c67f 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,23 @@
# ARM CPU Frequency scaling drivers
#
+config ACPI_CPPC_CPUFREQ
+ tristate "CPUFreq driver based on the ACPI CPPC spec"
+ depends on ACPI_PROCESSOR
+ select ACPI_CPPC_LIB
+ default n
+ help
+ This adds a CPUFreq driver which uses CPPC methods
+ as described in the ACPIv5.1 spec. CPPC stands for
+ Collaborative Processor Performance Controls. It
+ is based on an abstract continuous scale of CPU
+ performance values which allows the remote power
+ processor to flexibly optimize for power and
+ performance. CPPC relies on power management firmware
+ support for its operation.
+
+ If in doubt, say N.
+
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
@@ -12,6 +29,30 @@ config ARM_BIG_LITTLE_CPUFREQ
help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
+config ARM_DT_BL_CPUFREQ
+ tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && OF
+ help
+ This enables probing via DT for Generic CPUfreq driver for ARM
+ big.LITTLE platform. This gets frequency tables from DT.
+
+config ARM_VEXPRESS_SPC_CPUFREQ
+ tristate "Versatile Express SPC based CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
+ help
+ This add the CPUfreq driver support for Versatile Express
+ big.LITTLE platforms using SPC for power management.
+
+config ARM_SCPI_CPUFREQ
+ tristate "SCPI based CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
+ help
+ This adds the CPUfreq driver support for ARM big.LITTLE platforms
+ using SCPI protocol for CPU power management.
+
+ This driver uses SCPI Message Protocol driver to interact with the
+ firmware providing the CPU DVFS functionality.
+
config ARM_BRCMSTB_AVS_CPUFREQ
tristate "Broadcom STB AVS CPUfreq driver"
depends on ARCH_BRCMSTB || COMPILE_TEST
@@ -33,20 +74,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
If in doubt, say N.
-config ARM_DT_BL_CPUFREQ
- tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
- depends on ARM_BIG_LITTLE_CPUFREQ && OF
- help
- This enables probing via DT for Generic CPUfreq driver for ARM
- big.LITTLE platform. This gets frequency tables from DT.
-
-config ARM_VEXPRESS_SPC_CPUFREQ
- tristate "Versatile Express SPC based CPUfreq driver"
- depends on ARM_BIG_LITTLE_CPUFREQ && ARCH_VEXPRESS_SPC
- help
- This add the CPUfreq driver support for Versatile Express
- big.LITTLE platforms using SPC for power management.
-
config ARM_EXYNOS5440_CPUFREQ
tristate "SAMSUNG EXYNOS5440"
depends on SOC_EXYNOS5440
@@ -205,16 +232,6 @@ config ARM_SA1100_CPUFREQ
config ARM_SA1110_CPUFREQ
bool
-config ARM_SCPI_CPUFREQ
- tristate "SCPI based CPUfreq driver"
- depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
- help
- This adds the CPUfreq driver support for ARM big.LITTLE platforms
- using SCPI protocol for CPU power management.
-
- This driver uses SCPI Message Protocol driver to interact with the
- firmware providing the CPU DVFS functionality.
-
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
depends on PLAT_SPEAR
@@ -275,20 +292,3 @@ config ARM_PXA2xx_CPUFREQ
This add the CPUFreq driver support for Intel PXA2xx SOCs.
If in doubt, say N.
-
-config ACPI_CPPC_CPUFREQ
- tristate "CPUFreq driver based on the ACPI CPPC spec"
- depends on ACPI_PROCESSOR
- select ACPI_CPPC_LIB
- default n
- help
- This adds a CPUFreq driver which uses CPPC methods
- as described in the ACPIv5.1 spec. CPPC stands for
- Collaborative Processor Performance Controls. It
- is based on an abstract continuous scale of CPU
- performance values which allows the remote power
- processor to flexibly optimize for power and
- performance. CPPC relies on power management firmware
- support for its operation.
-
- If in doubt, say N.
--
2.15.0
^ permalink raw reply related
* [PATCH 1/6] dt-bindings: marvell: Add documentation for the North Bridge PM on Armada 37xx
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201112508.14121-1-gregory.clement@free-electrons.com>
Extend the documentation of the Armada 37xx SoC with the the North
Bridge Power Management component.
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
.../devicetree/bindings/arm/marvell/armada-37xx.txt | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
index 51336e5fc761..7ad9830d9177 100644
--- a/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
+++ b/Documentation/devicetree/bindings/arm/marvell/armada-37xx.txt
@@ -14,3 +14,22 @@ following property before the previous one:
Example:
compatible = "marvell,armada-3720-db", "marvell,armada3720", "marvell,armada3710";
+
+
+Power management
+----------------
+
+For power management (particularly DVFS and AVS), the North Bridge
+Power Management component is needed:
+
+Required properties:
+- compatible : should contain "marvell,armada-3700-nb-pm", "syscon";
+- reg : the register start and length for the North Bridge
+ Power Management
+
+Example:
+
+nb_pm: nb_pm at 14000 {
+ compatible = "marvell,armada-3700-nb-pm", "syscon";
+ reg = <0x14000 0x60>;
+}
--
2.15.0
^ permalink raw reply related
* [PATCH 0/6] Add CPU Frequency scaling support on Armada 37xx
From: Gregory CLEMENT @ 2017-12-01 11:25 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds the CPU Frequency support on Armada 37xx using
DVFS. It is based on the initial work of Evan Wang and Victor Gu.
DVFS control is done by a set of registers from the North Bridge Power
Management block. The binding for this block is documented in patch 1.
While adding a new cpufreq driver I found that the Kconfig and
Makefile were no more in order, so it is fixed by patch 2 and 3.
The 4th patch is just about updating the MAINTAINERS file with the new
driver.
The next patch is the real purpose of the series. The main goal of
this driver is to setup the CPU load level in the hardware to
associate them to CPU frequencies and register a standard cpufreq
driver. Note that the hardware also capable of doing AVS (Adaptive
Voltage Scaling), by associating a voltage on each level beside the
CPU frequency. However, this support is not yet ready, so it is not
part of this series.
Finally, the last patch is for arm-soc the arm-soc subsystem through
mvebu and update the device tree to support the CPU frequency scaling.
An update on the CPU clock driver is needed in order to take into
account the DVFS setting. It's the purpose of an other series already
sent, but is no dependencies between the series (for building or at
runtime).
Thanks,
Gregory
Gregory CLEMENT (6):
dt-bindings: marvell: Add documentation for the North Bridge PM on
Armada 37xx
cpufreq: ARM: sort the Kconfig menu
cpufreq: sort the drivers in ARM part
MAINTAINERS: add new entries for Armada 37xx cpufreq driver
cpufreq: Add DVFS support for Armada 37xx
arm64: dts: marvell: armada-37xx: add nodes allowing cpufreq support
.../bindings/arm/marvell/armada-37xx.txt | 19 ++
MAINTAINERS | 1 +
arch/arm64/boot/dts/marvell/armada-372x.dtsi | 1 +
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 7 +
drivers/cpufreq/Kconfig.arm | 89 ++++----
drivers/cpufreq/Makefile | 9 +-
drivers/cpufreq/armada-37xx-cpufreq.c | 241 +++++++++++++++++++++
7 files changed, 322 insertions(+), 45 deletions(-)
create mode 100644 drivers/cpufreq/armada-37xx-cpufreq.c
--
2.15.0
^ permalink raw reply
* [PATCH v4 2/2] arm64: Add software workaround for Falkor erratum 1041
From: Will Deacon @ 2017-12-01 11:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1511824680-16397-3-git-send-email-shankerd@codeaurora.org>
On Mon, Nov 27, 2017 at 05:18:00PM -0600, Shanker Donthineni wrote:
> The ARM architecture defines the memory locations that are permitted
> to be accessed as the result of a speculative instruction fetch from
> an exception level for which all stages of translation are disabled.
> Specifically, the core is permitted to speculatively fetch from the
> 4KB region containing the current program counter 4K and next 4K.
>
> When translation is changed from enabled to disabled for the running
> exception level (SCTLR_ELn[M] changed from a value of 1 to 0), the
> Falkor core may errantly speculatively access memory locations outside
> of the 4KB region permitted by the architecture. The errant memory
> access may lead to one of the following unexpected behaviors.
>
> 1) A System Error Interrupt (SEI) being raised by the Falkor core due
> to the errant memory access attempting to access a region of memory
> that is protected by a slave-side memory protection unit.
> 2) Unpredictable device behavior due to a speculative read from device
> memory. This behavior may only occur if the instruction cache is
> disabled prior to or coincident with translation being changed from
> enabled to disabled.
>
> The conditions leading to this erratum will not occur when either of the
> following occur:
> 1) A higher exception level disables translation of a lower exception level
> (e.g. EL2 changing SCTLR_EL1[M] from a value of 1 to 0).
> 2) An exception level disabling its stage-1 translation if its stage-2
> translation is enabled (e.g. EL1 changing SCTLR_EL1[M] from a value of 1
> to 0 when HCR_EL2[VM] has a value of 1).
>
> To avoid the errant behavior, software must execute an ISB immediately
> prior to executing the MSR that will change SCTLR_ELn[M] from 1 to 0.
>
> Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
> ---
> Changes since v3:
> Rebased to kernel v4.15-rc1.
> Changes since v2:
> Repost the corrected patches.
> Changes since v1:
> Apply the workaround where it's required.
>
> Documentation/arm64/silicon-errata.txt | 1 +
> arch/arm64/Kconfig | 12 +++++++++++-
> arch/arm64/include/asm/assembler.h | 19 +++++++++++++++++++
> arch/arm64/include/asm/cpucaps.h | 3 ++-
> arch/arm64/kernel/cpu-reset.S | 1 +
> arch/arm64/kernel/cpu_errata.c | 16 ++++++++++++++++
> arch/arm64/kernel/efi-entry.S | 2 ++
> arch/arm64/kernel/head.S | 1 +
> arch/arm64/kernel/relocate_kernel.S | 1 +
> arch/arm64/kvm/hyp-init.S | 1 +
This is an awful lot of code just to add an ISB instruction prior to
disabling the MMU. Why do you need to go through the alternatives framework
for this? Just do it with an #ifdef; this isn't a fastpath.
Will
^ permalink raw reply
* [patch v12 2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx families JTAG master driver
From: Oleksandr Shamray @ 2017-12-01 11:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGMNF6XRwU5QEJhkg-mVwE5zpPigtcGJtRUupZHtcWRdedcsxg@mail.gmail.com>
> -----Original Message-----
> From: Kun Yi [mailto:kunyi at google.com]
> Sent: Thursday, November 30, 2017 12:51 AM
> To: Oleksandr Shamray <oleksandrs@mellanox.com>
> Cc: gregkh at linuxfoundation.org; arnd at arndb.de; system-sw-low-level
> <system-sw-low-level@mellanox.com>; devicetree at vger.kernel.org;
> jiri at resnulli.us; Vadim Pasternak <vadimp@mellanox.com>; linux-
> api at vger.kernel.org; OpenBMC Maillist <openbmc@lists.ozlabs.org>; linux-
> kernel at vger.kernel.org; openocd-devel-owner at lists.sourceforge.net;
> mec at shout.net; Jiri Pirko <jiri@mellanox.com>; robh+dt at kernel.org; linux-
> serial at vger.kernel.org; tklauser at distanz.ch; mchehab at kernel.org;
> davem at davemloft.net; linux-arm-kernel at lists.infradead.org
> Subject: Re: [patch v12 2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx
> families JTAG master driver
>
> Thanks for working on the driver, Oleksandr. I gave this a try on a board with
> Aspeed 2520. One question below:
>
> On Tue, Nov 14, 2017 at 8:11 AM, Oleksandr Shamray
> <oleksandrs@mellanox.com> wrote:
> > Driver adds support of Aspeed 2500/2400 series SOC JTAG master controller.
> >
> > Driver implements the following jtag ops:
> > - freq_get;
> > - freq_set;
> > - status_get;
> > - idle;
> > - xfer;
> >
[..]
> > +
> > +static const struct jtag_ops aspeed_jtag_ops = {
> > + .freq_get = aspeed_jtag_freq_get,
> > + .freq_set = aspeed_jtag_freq_set,
> > + .status_get = aspeed_jtag_status_get,
> > + .idle = aspeed_jtag_idle,
> > + .xfer = aspeed_jtag_xfer,
> > + .mode_set = aspeed_jtag_mode_set };
> > +
> > +static int aspeed_jtag_probe(struct platform_device *pdev) {
> > + struct aspeed_jtag *aspeed_jtag;
> > + struct jtag *jtag;
> > + int err;
> > +
> > + if (!of_device_is_compatible(pdev->dev.of_node,
> > + "aspeed,aspeed-jtag"))
>
> Should this be "aspeed,ast2400-jtag"/"aspeed,ast2500-jtag" as specified in the
> compatible string below?
>
Yes
> > + return -ENOMEM;
> > +
> > + jtag = jtag_alloc(sizeof(*aspeed_jtag), &aspeed_jtag_ops);
> > + if (!jtag)
> > + return -ENODEV;
> > +
> > + platform_set_drvdata(pdev, jtag);
> > + aspeed_jtag = jtag_priv(jtag);
> > + aspeed_jtag->dev = &pdev->dev;
> > +
[..]
> > +
> > +MODULE_AUTHOR("Oleksandr Shamray <oleksandrs@mellanox.com>");
> > +MODULE_DESCRIPTION("ASPEED JTAG driver"); MODULE_LICENSE("GPL
> v2");
> > --
> > 1.7.1
> >
> --
> Regards,
> Kun
Thanks.
BR
Oleksandr Shamray
^ permalink raw reply
* [PATCH v2 0/4] ARM: dts: renesas: Convert to named i2c-gpio bindings
From: Wolfram Sang @ 2017-12-01 11:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201081850.4tqbnlvxdax7phfs@verge.net.au>
On Fri, Dec 01, 2017 at 09:18:55AM +0100, Simon Horman wrote:
> On Thu, Nov 30, 2017 at 01:57:22PM +0100, Geert Uytterhoeven wrote:
> > Hi Simon, Magnus,
> >
> > Commits 7d29f509d2cfd807 ("dt-bindings: i2c: i2c-gpio: Add support for
> > named gpios") and 05c74778858d7d99 ("i2c: gpio: Add support for named
> > gpios in DT") introduced named i2c-gpio DT bindings, and deprecated the
> > more error-prone unnamed variant.
> >
> > This patch series switches all Renesas boards to the new bindings, and
> > adds the missing GPIO_OPEN_DRAIN I/O flags, which were implicitly
> > assumed before. The latter gets rid of messages like:
> >
> > gpio-208 (?): enforced open drain please flag it properly in DT/ACPI DSDT/board file
> > gpio-91 (?): enforced open drain please flag it properly in DT/ACPI DSDT/board file
> >
> > Patch 1 was extracted from series "[PATCH/RFC 0/3] i2c: gpio: Add
> > support for named gpios in DT", hence the v2. All other patches are
> > new.
> >
> > Note that after this series is applied, the i2c-gpio buses are no longer
> > detected when booting new DTBs on old (v4.14 and older) kernels, which
> > should not be an issue. Booting old DTBs on new kernels is not
> > affected.
> >
> > Thanks for applying!
>
> Thanks, applied.
Phew, you guys are fast. For the record:
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.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/20171201/85d3a398/attachment.sig>
^ permalink raw reply
* [PATCH 5/5] mtd: nand: add ->exec_op() implementation
From: Boris Brezillon @ 2017-12-01 11:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130170132.27522-6-miquel.raynal@free-electrons.com>
On Thu, 30 Nov 2017 18:01:32 +0100
Miquel Raynal <miquel.raynal@free-electrons.com> wrote:
> EXPORT_SYMBOL_GPL(nand_write_data_op);
>
> /**
> + * struct nand_op_parser_ctx - Context used by the parser
> + * @instrs: array of all the instructions that must be addressed
> + * @ninstrs: length of the @instrs array
> + * @instr_idx: index of the instruction in the @instrs array that matches the
> + * first instruction of the subop structure
> + * @instr_start_off: offset at which the first instruction of the subop
> + * structure must start if it is and address or a data
^ an
> + * instruction
@subop is missing.
> + *
> + * This structure is used by the core to handle splitting lengthy instructions
> + * into sub-operations.
Not only lengthy instructions (data or addr instructions that are too
long to be handled in one go), it also helps splitting an operation into
sub-operations that the NAND controller can handle.
I think you should just say:
"
This structure is used by the core to split NAND operations into
sub-operations that can be handled by the NAND controller
"
> + */
> +struct nand_op_parser_ctx {
> + const struct nand_op_instr *instrs;
> + unsigned int ninstrs;
> + unsigned int instr_idx;
> + unsigned int instr_start_off;
> + struct nand_subop subop;
> +};
> +
> +/**
> + * nand_op_parser_must_split_instr - Checks if an instruction must be split
> + * @pat: the parser pattern that match
*matches
and this is a pattern element, not the whole pattern
> + * @instr: the instruction array to check
That's not true, in this function you only check a single intruction,
not the whole array.
> + * @start_offset: the offset from which to start in the first instruction of the
> + * @instr array
Again @instr is not treated as an array in this function. An maybe you
should say that @start_offset is updated with the new context offset
when the function returns true.
> + *
> + * Some NAND controllers are limited and cannot send X address cycles with a
> + * unique operation, or cannot read/write more than Y bytes at the same time.
> + * In this case, split the instruction that does not fit in a single
> + * controller-operation into two or more chunks.
> + *
> + * Returns true if the instruction must be split, false otherwise.
> + * The @start_offset parameter is also updated to the offset at which the next
> + * bundle of instruction must start (if an address or a data instruction).
Okay, you say it here. Better move this explanation next to the param
definition.
> + */
> +static bool
> +nand_op_parser_must_split_instr(const struct nand_op_parser_pattern_elem *pat,
> + const struct nand_op_instr *instr,
> + unsigned int *start_offset)
> +{
> + switch (pat->type) {
> + case NAND_OP_ADDR_INSTR:
> + if (!pat->addr.maxcycles)
> + break;
> +
> + if (instr->ctx.addr.naddrs - *start_offset >
> + pat->addr.maxcycles) {
> + *start_offset += pat->addr.maxcycles;
> + return true;
> + }
> + break;
> +
> + case NAND_OP_DATA_IN_INSTR:
> + case NAND_OP_DATA_OUT_INSTR:
> + if (!pat->data.maxlen)
> + break;
> +
> + if (instr->ctx.data.len - *start_offset > pat->data.maxlen) {
> + *start_offset += pat->data.maxlen;
> + return true;
> + }
> + break;
> +
> + default:
> + break;
> + }
> +
> + return false;
> +}
> +
> +/**
> + * nand_op_parser_match_pat - Checks a pattern
Checks if a pattern matches the
instructions remaining in the parser
context
> + * @pat: the parser pattern to check if it matches
^ pattern to test
> + * @ctx: the context structure to match with the pattern @pat
^ parser context
> + *
> + * Check if *one* given pattern matches the given sequence of instructions
Check if @pat matches the set or a sub-set of instructions
remaining in @ctx. Returns true if this is the case, false
otherwise. When true is returned @ctx->subop is updated with
the set of instructions to be passed to the controller driver.
> + */
> +static bool
> +nand_op_parser_match_pat(const struct nand_op_parser_pattern *pat,
> + struct nand_op_parser_ctx *ctx)
> +{
> + unsigned int i, j, boundary_off = ctx->instr_start_off;
> +
> + ctx->subop.ninstrs = 0;
> +
> + for (i = ctx->instr_idx, j = 0; i < ctx->ninstrs && j < pat->nelems;) {
> + const struct nand_op_instr *instr = &ctx->instrs[i];
> +
> + /*
> + * The pattern instruction does not match the operation
> + * instruction. If the instruction is marked optional in the
> + * pattern definition, we skip the pattern element and continue
> + * to the next one. If the element is mandatory, there's no
> + * match and we can return false directly.
> + */
> + if (instr->type != pat->elems[j].type) {
> + if (!pat->elems[j].optional)
> + return false;
> +
> + j++;
> + continue;
> + }
> +
> + /*
> + * Now check the pattern element constraints. If the pattern is
> + * not able to handle the whole instruction in a single step,
> + * we'll have to break it down into several instructions.
> + * The *boudary_off value comes back updated to point to the
> + * limit between the split instruction (the end of the original
> + * chunk, the start of new next one).
> + */
> + if (nand_op_parser_must_split_instr(&pat->elems[j], instr,
> + &boundary_off)) {
> + ctx->subop.ninstrs++;
> + j++;
> + break;
> + }
> +
> + ctx->subop.ninstrs++;
> + i++;
> + j++;
> + boundary_off = 0;
> + }
> +
> + /*
> + * This can happen if all instructions of a pattern are optional.
> + * Still, if there's not at least one instruction handled by this
> + * pattern, this is not a match, and we should try the next one (if
> + * any).
> + */
> + if (!ctx->subop.ninstrs)
> + return false;
> +
> + /*
> + * We had a match on the pattern head, but the pattern may be longer
> + * than the instructions we're asked to execute. We need to make sure
> + * there's no mandatory elements in the pattern tail.
> + *
> + * The case where all the operations of a pattern have been checked but
> + * the number of instructions is bigger is handled right after this by
> + * returning true on the pattern match, which will order the execution
> + * of the subset of instructions later defined, while updating the
> + * context ids to the next chunk of instructions.
> + */
> + for (; j < pat->nelems; j++) {
> + if (!pat->elems[j].optional)
> + return false;
> + }
> +
> + /*
> + * We have a match: update the ctx and return true. The subop structure
> + * will be used by the pattern's ->exec() function.
> + */
> + ctx->subop.instrs = &ctx->instrs[ctx->instr_idx];
> + ctx->subop.first_instr_start_off = ctx->instr_start_off;
> + ctx->subop.last_instr_end_off = boundary_off;
> +
> + /*
> + * Update the pointers so the calling function will be able to recall
> + * this one with a new subset of instructions.
> + *
> + * In the case where the last operation of this set is split, point to
> + * the last unfinished job, knowing the starting offset.
> + */
> + ctx->instr_idx = i;
> + ctx->instr_start_off = boundary_off;
> +
> + return true;
> +}
> +
> +#if IS_ENABLED(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
> +static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
> +{
> + const struct nand_op_instr *instr;
> + char *prefix = " ";
> + char *buf;
> + unsigned int len, off = 0;
> + int i, j;
> +
> + pr_debug("executing subop:\n");
> +
> + for (i = 0; i < ctx->ninstrs; i++) {
> + instr = &ctx->instrs[i];
> +
> + /*
> + * ctx->instr_idx is not reliable because it may already have
> + * been updated by the parser. Use pointers comparison instead.
> + */
> + if (instr == &ctx->subop.instrs[0])
> + prefix = " ->";
> +
> + switch (instr->type) {
> + case NAND_OP_CMD_INSTR:
> + pr_debug("%sCMD [0x%02x]\n", prefix,
> + instr->ctx.cmd.opcode);
> + break;
> + case NAND_OP_ADDR_INSTR:
> + /*
> + * A log line is much less than 50 bytes, plus 5 bytes
> + * per address cycle to display.
> + */
> + len = 50 + 5 * instr->ctx.addr.naddrs;
> + buf = kzalloc(len, GFP_KERNEL);
> + if (!buf)
> + return;
> +
> + off += snprintf(buf, len, "ADDR [%d cyc:",
> + instr->ctx.addr.naddrs);
> + for (j = 0; j < instr->ctx.addr.naddrs; j++)
> + off += snprintf(&buf[off], len - off,
> + " 0x%02x",
> + instr->ctx.addr.addrs[j]);
> + pr_debug("%s%s]\n", prefix, buf);
> + break;
> + case NAND_OP_DATA_IN_INSTR:
> + pr_debug("%sDATA_IN [%d B%s]\n", prefix,
> + instr->ctx.data.len,
> + instr->ctx.data.force_8bit ?
> + ", force 8-bit" : "");
> + break;
> + case NAND_OP_DATA_OUT_INSTR:
> + pr_debug("%sDATA_OUT [%d B%s]\n", prefix,
> + instr->ctx.data.len,
> + instr->ctx.data.force_8bit ?
> + ", force 8-bit" : "");
> + break;
> + case NAND_OP_WAITRDY_INSTR:
> + pr_debug("%sWAITRDY [max %d ms]\n", prefix,
> + instr->ctx.waitrdy.timeout_ms);
> + break;
> + }
> +
> + if (instr == &ctx->subop.instrs[ctx->subop.ninstrs - 1])
> + prefix = " ";
> + }
> +}
> +#else
> +static void nand_op_parser_trace(const struct nand_op_parser_ctx *ctx)
> +{
> + /* NOP */
> +}
> +#endif
> +
> +/**
> + * nand_op_parser_exec_op - exec_op parser
> + * @chip: the NAND chip
> + * @parser: the parser to use given by the controller driver
patterns description provided by the controller driver
> + * @op: the NAND operation to address
> + * @check_only: flag asking if the entire operation could be handled
when true, the function only checks if @op can be
handled but does not execute the operation
> + *
> + * Function that must be called by each driver that implement the "exec_op API"
> + * in their own ->exec_op() implementation.
> + *
> + * The function iterates on all the instructions asked and make use of internal
> + * parsers to find matches between the instruction list and the handled patterns
> + * filled by the controller drivers inside the @parser structure. If needed, the
> + * instructions could be split into sub-operations and be executed sequentially.
Helper function designed to ease integration of NAND controller
drivers that only support a limited set of instruction sequences.
The supported sequences are described in @parser, and the
framework takes care of splitting @op into multi sub-operations
(if required) and pass them back to @pattern->exec() if
@check_only is set to false.
NAND controller drivers should call this function from their
->exec_op() implementation.
> + */
> +int nand_op_parser_exec_op(struct nand_chip *chip,
> + const struct nand_op_parser *parser,
> + const struct nand_operation *op, bool check_only)
> +{
> + struct nand_op_parser_ctx ctx = {
> + .instrs = op->instrs,
> + .ninstrs = op->ninstrs,
> + };
> + unsigned int i;
> +
> + while (ctx.instr_idx < op->ninstrs) {
> + int ret;
> +
> + for (i = 0; i < parser->npatterns; i++) {
> + const struct nand_op_parser_pattern *pattern;
> +
> + pattern = &parser->patterns[i];
> + if (!nand_op_parser_match_pat(pattern, &ctx))
> + continue;
> +
> + nand_op_parser_trace(&ctx);
> +
> + if (check_only)
> + break;
> +
> + ret = pattern->exec(chip, &ctx.subop);
> + if (ret)
> + return ret;
> +
> + break;
> + }
> +
> + if (i == parser->npatterns) {
> + pr_debug("->exec_op() parser: pattern not found!\n");
> + return -ENOTSUPP;
> + }
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(nand_op_parser_exec_op);
> +
> +static bool nand_instr_is_data(const struct nand_op_instr *instr)
> +{
> + return instr && (instr->type == NAND_OP_DATA_IN_INSTR ||
> + instr->type == NAND_OP_DATA_OUT_INSTR);
> +}
> +
> +static bool nand_subop_instr_is_valid(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + return subop && instr_idx < subop->ninstrs;
> +}
> +
> +static int nand_subop_get_start_off(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + if (instr_idx)
> + return 0;
> +
> + return subop->first_instr_start_off;
> +}
> +
> +/**
> + * nand_subop_get_addr_start_off - Get the start offset in an address array
> + * @subop: The entire sub-operation
> + * @instr_idx: Index of the instruction inside the sub-operation
> + *
> + * Instructions arrays may be split by the parser between instructions,
> + * and also in the middle of an address instruction if the number of cycles
> + * to assert in one operation is not supported by the controller.
s/assert/send/ or s/assert/issue/
> + *
> + * For this, instead of using the first index of the ->addr.addrs field from the
> + * address instruction, the NAND controller driver must use this helper that
> + * will either return 0 if the index does not point to the first instruction of
> + * the sub-operation, or the offset of the next starting offset inside the
> + * address cycles.
Wow, I'm lost. Can we just drop this paragraph?
> + *
> + * Returns the offset of the first address cycle to assert from the pointed
> + * address instruction.
This is not clear either, but I can't find a clearer explanation right
now.
> + */
> +int nand_subop_get_addr_start_off(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + if (!nand_subop_instr_is_valid(subop, instr_idx) ||
> + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
> + return -EINVAL;
> +
> + return nand_subop_get_start_off(subop, instr_idx);
> +}
> +EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off);
> +
> +/**
> + * nand_subop_get_num_addr_cyc - Get the remaining address cycles to assert
> + * @subop: The entire sub-operation
> + * @instr_idx: Index of the instruction inside the sub-operation
> + *
> + * Instructions arrays may be split by the parser between instructions,
> + * and also in the middle of an address instruction if the number of cycles
> + * to assert in one operation is not supported by the controller.
Ditto, we can drop this explanation.
> + *
> + * Returns the number of address cycles to assert from the pointed address
> + * instruction.
Returns the number of address cycles to issue.
> + */
> +int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + int start_off, end_off;
> +
> + if (!nand_subop_instr_is_valid(subop, instr_idx) ||
> + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)
> + return -EINVAL;
> +
> + start_off = nand_subop_get_addr_start_off(subop, instr_idx);
> +
> + if (instr_idx == subop->ninstrs - 1 &&
> + subop->last_instr_end_off)
> + end_off = subop->last_instr_end_off;
> + else
> + end_off = subop->instrs[instr_idx].ctx.addr.naddrs;
> +
> + return end_off - start_off;
> +}
> +EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc);
> +
> +/**
> + * nand_subop_get_data_start_off - Get the start offset in a data array
> + * @subop: The entire sub-operation
> + * @instr_idx: Index of the instruction inside the sub-operation
> + *
> + * Instructions arrays may be split by the parser between instructions,
> + * and also in the middle of a data instruction if the number of bytes to access
> + * in one operation is greater that the controller limit.
> + *
> + * Returns the data offset inside the pointed data instruction buffer from which
> + * to start.
Ditto: let's find a clearer way to explain what this function does.
> + */
> +int nand_subop_get_data_start_off(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + if (!nand_subop_instr_is_valid(subop, instr_idx) ||
> + !nand_instr_is_data(&subop->instrs[instr_idx]))
> + return -EINVAL;
> +
> + return nand_subop_get_start_off(subop, instr_idx);
> +}
> +EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off);
> +
> +/**
> + * nand_subop_get_data_len - Get the number of bytes to retrieve
> + * @subop: The entire sub-operation
> + * @instr_idx: Index of the instruction inside the sub-operation
> + *
> + * Instructions arrays may be split by the parser between instructions,
> + * and also in the middle of a data instruction if the number of bytes to access
> + * in one operation is greater that the controller limit.
> + *
> + * For this, instead of using the ->data.len field from the data instruction,
> + * the NAND controller driver must use this helper that will return the actual
> + * length of data to move between the first and last offset asked for this
> + * particular instruction.
> + *
> + * Returns the length of the data to move from the pointed data instruction.
Ditto.
> + */
> +int nand_subop_get_data_len(const struct nand_subop *subop,
> + unsigned int instr_idx)
> +{
> + int start_off = 0, end_off;
> +
> + if (!nand_subop_instr_is_valid(subop, instr_idx) ||
> + !nand_instr_is_data(&subop->instrs[instr_idx]))
> + return -EINVAL;
> +
> + start_off = nand_subop_get_data_start_off(subop, instr_idx);
> +
> + if (instr_idx == subop->ninstrs - 1 &&
> + subop->last_instr_end_off)
> + end_off = subop->last_instr_end_off;
> + else
> + end_off = subop->instrs[instr_idx].ctx.data.len;
> +
> + return end_off - start_off;
> +}
> +EXPORT_SYMBOL_GPL(nand_subop_get_data_len);
> +
> +/**
> * nand_reset - Reset and initialize a NAND device
> * @chip: The NAND chip
> * @chipnr: Internal die id
> @@ -4002,11 +4977,11 @@ static void nand_set_defaults(struct nand_chip *chip)
> chip->chip_delay = 20;
>
> /* check, if a user supplied command function given */
> - if (chip->cmdfunc == NULL)
> + if (!chip->cmdfunc && !chip->exec_op)
> chip->cmdfunc = nand_command;
>
> /* check, if a user supplied wait function given */
> - if (chip->waitfunc == NULL)
> + if (!chip->waitfunc)
> chip->waitfunc = nand_wait;
>
> if (!chip->select_chip)
> @@ -4894,15 +5869,21 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
> if (!mtd->name && mtd->dev.parent)
> mtd->name = dev_name(mtd->dev.parent);
>
> - if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
> + /*
> + * ->cmdfunc() is legacy and will only be used if ->exec_op() is not
> + * populated.
> + */
> + if (!chip->exec_op) {
> /*
> - * Default functions assigned for chip_select() and
> - * cmdfunc() both expect cmd_ctrl() to be populated,
> - * so we need to check that that's the case
> + * Default functions assigned for ->cmdfunc() and
> + * ->select_chip() both expect ->cmd_ctrl() to be populated.
> */
> - pr_err("chip.cmd_ctrl() callback is not provided");
> - return -EINVAL;
> + if ((!chip->cmdfunc || !chip->select_chip) && !chip->cmd_ctrl) {
> + pr_err("->cmd_ctrl() should be provided\n");
> + return -EINVAL;
> + }
> }
> +
> /* Set the default functions */
> nand_set_defaults(chip);
>
> diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c
> index bae0da2aa2a8..d542908a0ebb 100644
> --- a/drivers/mtd/nand/nand_hynix.c
> +++ b/drivers/mtd/nand/nand_hynix.c
> @@ -81,6 +81,15 @@ static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd)
> {
> struct mtd_info *mtd = nand_to_mtd(chip);
>
> + if (chip->exec_op) {
> + struct nand_op_instr instrs[] = {
> + NAND_OP_CMD(cmd, 0),
> + };
> + struct nand_operation op = NAND_OPERATION(instrs);
> +
> + return nand_exec_op(chip, &op);
> + }
> +
> chip->cmdfunc(mtd, cmd, -1, -1);
>
> return 0;
> diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
> index 0be959a478db..053b506f4800 100644
> --- a/include/linux/mtd/rawnand.h
> +++ b/include/linux/mtd/rawnand.h
> @@ -751,6 +751,349 @@ struct nand_manufacturer_ops {
> };
>
> /**
> + * struct nand_op_cmd_instr - Definition of a command instruction
> + * @opcode: the command to assert in one cycle
> + */
> +struct nand_op_cmd_instr {
> + u8 opcode;
> +};
> +
> +/**
> + * struct nand_op_addr_instr - Definition of an address instruction
> + * @naddrs: length of the @addrs array
> + * @addrs: array containing the address cycles to assert
> + */
> +struct nand_op_addr_instr {
> + unsigned int naddrs;
> + const u8 *addrs;
> +};
> +
> +/**
> + * struct nand_op_data_instr - Definition of a data instruction
> + * @len: number of data bytes to move
> + * @in: buffer to fill when reading from the NAND chip
> + * @out: buffer to read from when writing to the NAND chip
> + * @force_8bit: force 8-bit access
> + *
> + * Please note that "in" and "out" are inverted from the ONFI specification
> + * and are from the controller perspective, so a "in" is a read from the NAND
> + * chip while a "out" is a write to the NAND chip.
> + */
> +struct nand_op_data_instr {
> + unsigned int len;
> + union {
> + void *in;
> + const void *out;
> + } buf;
> + bool force_8bit;
> +};
> +
> +/**
> + * struct nand_op_waitrdy_instr - Definition of a wait ready instruction
> + * @timeout_ms: maximum delay while waiting for the ready/busy pin in ms
> + */
> +struct nand_op_waitrdy_instr {
> + unsigned int timeout_ms;
> +};
> +
> +/**
> + * enum nand_op_instr_type - Enumeration of all instruction types
> + * @NAND_OP_CMD_INSTR: command instruction
> + * @NAND_OP_ADDR_INSTR: address instruction
> + * @NAND_OP_DATA_IN_INSTR: data in instruction
> + * @NAND_OP_DATA_OUT_INSTR: data out instruction
> + * @NAND_OP_WAITRDY_INSTR: wait ready instruction
> + */
> +enum nand_op_instr_type {
> + NAND_OP_CMD_INSTR,
> + NAND_OP_ADDR_INSTR,
> + NAND_OP_DATA_IN_INSTR,
> + NAND_OP_DATA_OUT_INSTR,
> + NAND_OP_WAITRDY_INSTR,
> +};
> +
> +/**
> + * struct nand_op_instr - Generic definition of an instruction
> + * @type: an enumeration of the instruction type
> + * @cmd/@addr/@data/@waitrdy: extra data associated to the instruction.
> + * You'll have to use the appropriate element
> + * depending on @type
> + * @delay_ns: delay to apply by the controller after the instruction has been
> + * actually executed (most of them are directly handled by the
^ sent on the bus
> + * controllers once the timings negociation has been done)
> + */
> +struct nand_op_instr {
> + enum nand_op_instr_type type;
> + union {
> + struct nand_op_cmd_instr cmd;
> + struct nand_op_addr_instr addr;
> + struct nand_op_data_instr data;
> + struct nand_op_waitrdy_instr waitrdy;
> + } ctx;
> + unsigned int delay_ns;
> +};
> +
> +/*
> + * Special handling must be done for the WAITRDY timeout parameter as it usually
> + * is either tPROG (after a prog), tR (before a read), tRST (during a reset) or
> + * tBERS (during an erase) which all of them are u64 values that cannot be
> + * divided by usual kernel macros and must be handled with the special
> + * DIV_ROUND_UP_ULL() macro.
> + */
> +#define __DIVIDE(dividend, divisor) ({ \
> + sizeof(dividend) == sizeof(u32) ? \
> + DIV_ROUND_UP(dividend, divisor) : \
> + DIV_ROUND_UP_ULL(dividend, divisor); \
> + })
> +#define PSEC_TO_NSEC(x) __DIVIDE(x, 1000)
> +#define PSEC_TO_MSEC(x) __DIVIDE(x, 1000000000)
> +
> +#define NAND_OP_CMD(id, ns) \
> + { \
> + .type = NAND_OP_CMD_INSTR, \
> + .ctx.cmd.opcode = id, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_ADDR(ncycles, cycles, ns) \
> + { \
> + .type = NAND_OP_ADDR_INSTR, \
> + .ctx.addr = { \
> + .naddrs = ncycles, \
> + .addrs = cycles, \
> + }, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_DATA_IN(l, buf, ns) \
> + { \
> + .type = NAND_OP_DATA_IN_INSTR, \
> + .ctx.data = { \
> + .len = l, \
> + .buf.in = buf, \
> + .force_8bit = false, \
> + }, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_DATA_OUT(l, buf, ns) \
> + { \
> + .type = NAND_OP_DATA_OUT_INSTR, \
> + .ctx.data = { \
> + .len = l, \
> + .buf.out = buf, \
> + .force_8bit = false, \
> + }, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_8BIT_DATA_IN(l, b, ns) \
> + { \
> + .type = NAND_OP_DATA_IN_INSTR, \
> + .ctx.data = { \
> + .len = l, \
> + .buf.in = b, \
> + .force_8bit = true, \
> + }, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_8BIT_DATA_OUT(l, b, ns) \
> + { \
> + .type = NAND_OP_DATA_OUT_INSTR, \
> + .ctx.data = { \
> + .len = l, \
> + .buf.out = b, \
> + .force_8bit = true, \
> + }, \
> + .delay_ns = ns, \
> + }
> +
> +#define NAND_OP_WAIT_RDY(tout_ms, ns) \
> + { \
> + .type = NAND_OP_WAITRDY_INSTR, \
> + .ctx.waitrdy.timeout_ms = tout_ms, \
> + .delay_ns = ns, \
> + }
> +
> +/**
> + * struct nand_subop - a sub operation
> + * @instrs: array of instructions
> + * @ninstrs: length of the @instrs array
> + * @first_instr_start_off: offset to start from for the first instruction
> + * of the sub-operation
> + * @last_instr_end_off: offset to end at (excluded) for the last instruction
> + * of the sub-operation
> + *
> + * Both parameters @first_instr_start_off and @last_instr_end_off apply for the
> + * address cycles in the case of address, or for data offset in the case of data
^ instructions
> + * transfers. Otherwise, it is irrelevant.
^ intructions
> + *
> + * When an operation cannot be handled as is by the NAND controller, it will
> + * be split by the parser and the remaining pieces will be handled as
into sub-operations which will be passed
to the controller driver.
> + * sub-operations.
> + */
> +struct nand_subop {
> + const struct nand_op_instr *instrs;
> + unsigned int ninstrs;
> + unsigned int first_instr_start_off;
> + unsigned int last_instr_end_off;
> +};
> +
> +int nand_subop_get_addr_start_off(const struct nand_subop *subop,
> + unsigned int op_id);
> +int nand_subop_get_num_addr_cyc(const struct nand_subop *subop,
> + unsigned int op_id);
> +int nand_subop_get_data_start_off(const struct nand_subop *subop,
> + unsigned int op_id);
> +int nand_subop_get_data_len(const struct nand_subop *subop,
> + unsigned int op_id);
> +
> +/**
> + * struct nand_op_parser_addr_constraints - Constraints for address instructions
> + * @maxcycles: maximum number of cycles that the controller can assert by
> + * instruction
> + */
> +struct nand_op_parser_addr_constraints {
> + unsigned int maxcycles;
> +};
> +
> +/**
> + * struct nand_op_parser_data_constraints - Constraints for data instructions
> + * @maxlen: maximum data length that the controller can handle with one
> + * instruction
> + */
> +struct nand_op_parser_data_constraints {
> + unsigned int maxlen;
> +};
> +
> +/**
> + * struct nand_op_parser_pattern_elem - One element of a pattern
> + * @type: the instructuction type
> + * @optional: if this element of the pattern is optional or mandatory
^ whether
> + * @addr/@data: address or data constraint (number of cycles or data length)
> + */
> +struct nand_op_parser_pattern_elem {
> + enum nand_op_instr_type type;
> + bool optional;
> + union {
> + struct nand_op_parser_addr_constraints addr;
> + struct nand_op_parser_data_constraints data;
> + };
> +};
> +
> +#define NAND_OP_PARSER_PAT_CMD_ELEM(_opt) \
> + { \
> + .type = NAND_OP_CMD_INSTR, \
> + .optional = _opt, \
> + }
> +
> +#define NAND_OP_PARSER_PAT_ADDR_ELEM(_opt, _maxcycles) \
> + { \
> + .type = NAND_OP_ADDR_INSTR, \
> + .optional = _opt, \
> + .addr.maxcycles = _maxcycles, \
> + }
> +
> +#define NAND_OP_PARSER_PAT_DATA_IN_ELEM(_opt, _maxlen) \
> + { \
> + .type = NAND_OP_DATA_IN_INSTR, \
> + .optional = _opt, \
> + .data.maxlen = _maxlen, \
> + }
> +
> +#define NAND_OP_PARSER_PAT_DATA_OUT_ELEM(_opt, _maxlen) \
> + { \
> + .type = NAND_OP_DATA_OUT_INSTR, \
> + .optional = _opt, \
> + .data.maxlen = _maxlen, \
> + }
> +
> +#define NAND_OP_PARSER_PAT_WAITRDY_ELEM(_opt) \
> + { \
> + .type = NAND_OP_WAITRDY_INSTR, \
> + .optional = _opt, \
> + }
> +
> +/**
> + * struct nand_op_parser_pattern - A complete pattern
> + * @elems: array of pattern elements
> + * @nelems: number of pattern elements in @elems array
> + * @exec: the function that will actually execute this pattern, written in the
> + * controller driver
> + *
> + * This is a complete pattern that is a list of elements, each one reprensenting
> + * one instruction with its constraints. Controller drivers must declare as much
> + * patterns as they support and give the list of the supported patterns (created
> + * with the help of the following macro) when calling nand_op_parser_exec_op()
> + * which is the preferred approach for advanced controllers as the main thing to
> + * do in the driver implementation of ->exec_op(). Once there is a match between
> + * the pattern and an operation, the either the core just wanted to know if the
(or a subset of this operation)
> + * operation was supporter (through the use of the check_only boolean) or it
> + * calls the @exec function to actually do the operation.
> + */
> +struct nand_op_parser_pattern {
> + const struct nand_op_parser_pattern_elem *elems;
> + unsigned int nelems;
> + int (*exec)(struct nand_chip *chip, const struct nand_subop *subop);
> +};
> +
^ permalink raw reply
* [PATCH 2/2] ahci: mtk: Change driver name to ahci-mtk
From: Matthias Brugger @ 2017-12-01 10:47 UTC (permalink / raw)
To: linux-arm-kernel
The driver name "ahci" is already used by the ahci platform driver.
This leads to the following error:
Error: Driver 'ahci' is already registered, aborting...
Change the name to ahci-mtk to fix this.
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
---
drivers/ata/ahci_mtk.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c
index 80854f71559a..22efb9370d1d 100644
--- a/drivers/ata/ahci_mtk.c
+++ b/drivers/ata/ahci_mtk.c
@@ -25,7 +25,7 @@
#include <linux/reset.h>
#include "ahci.h"
-#define DRV_NAME "ahci"
+#define DRV_NAME "ahci-mtk"
#define SYS_CFG 0x14
#define SYS_CFG_SATA_MSK GENMASK(31, 30)
--
2.12.3
^ permalink raw reply related
* [kernel-hardening][PATCH 3/3] arm: mm: dump: add checking for writable and executable pages
From: jinb.park @ 2017-12-01 10:43 UTC (permalink / raw)
To: linux-arm-kernel
Page mappings with full RWX permissions are a security risk.
x86, arm64 has an option to walk the page tables
and dump any bad pages.
(1404d6f13e47
("arm64: dump: Add checking for writable and exectuable pages"))
Add a similar implementation for arm.
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
arch/arm/Kconfig.debug | 27 +++++++++++++++
arch/arm/include/asm/ptdump.h | 8 +++++
arch/arm/mm/dump.c | 78 +++++++++++++++++++++++++++++++++++++++++++
arch/arm/mm/init.c | 2 ++
4 files changed, 115 insertions(+)
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index e7b94db..78a6470 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -20,6 +20,33 @@ config ARM_PTDUMP_DEBUGFS
kernel.
If in doubt, say "N"
+config DEBUG_WX
+ bool "Warn on W+X mappings at boot"
+ select ARM_PTDUMP_CORE
+ ---help---
+ Generate a warning if any W+X mappings are found at boot.
+
+ This is useful for discovering cases where the kernel is leaving
+ W+X mappings after applying NX, as such mappings are a security risk.
+
+ Look for a message in dmesg output like this:
+
+ arm/mm: Checked W+X mappings: passed, no W+X pages found.
+
+ or like this, if the check failed:
+
+ arm/mm: Checked W+X mappings: FAILED, <N> W+X pages found.
+
+ Note that even if the check fails, your kernel is possibly
+ still fine, as W+X mappings are not a security hole in
+ themselves, what they do is that they make the exploitation
+ of other unfixed kernel bugs easier.
+
+ There is no runtime or memory usage effect of this option
+ once the kernel has booted up - it's a one time check.
+
+ If in doubt, say "Y".
+
# RMK wants arm kernels compiled with frame pointers or stack unwinding.
# If you know what you are doing and are willing to live without stack
# traces, you can get a slightly smaller kernel by setting this option to
diff --git a/arch/arm/include/asm/ptdump.h b/arch/arm/include/asm/ptdump.h
index 3a6c0b7..b6a0162 100644
--- a/arch/arm/include/asm/ptdump.h
+++ b/arch/arm/include/asm/ptdump.h
@@ -43,6 +43,14 @@ static inline int ptdump_debugfs_register(struct ptdump_info *info,
}
#endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
+void ptdump_check_wx(void);
+
#endif /* CONFIG_ARM_PTDUMP_CORE */
+#ifdef CONFIG_DEBUG_WX
+#define debug_checkwx() ptdump_check_wx()
+#else
+#define debug_checkwx() do { } while (0)
+#endif
+
#endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 43a2bee..a0a4b30 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -52,6 +52,8 @@ struct pg_state {
unsigned long start_address;
unsigned level;
u64 current_prot;
+ bool check_wx;
+ unsigned long wx_pages;
const char *current_domain;
};
@@ -226,6 +228,60 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits, size_t
}
}
+static inline bool is_prot_ro(struct pg_state *st)
+{
+ if (st->level < 4) {
+ #ifdef CONFIG_ARM_LPAE
+ if ((st->current_prot &
+ (L_PMD_SECT_RDONLY | PMD_SECT_AP2)) ==
+ (L_PMD_SECT_RDONLY | PMD_SECT_AP2))
+ return true;
+ #elif __LINUX_ARM_ARCH__ >= 6
+ if ((st->current_prot &
+ (PMD_SECT_APX | PMD_SECT_AP_READ | PMD_SECT_AP_WRITE)) ==
+ (PMD_SECT_APX | PMD_SECT_AP_WRITE))
+ return true;
+ #else
+ if ((st->current_prot &
+ (PMD_SECT_AP_READ | PMD_SECT_AP_WRITE)) == 0)
+ return true;
+ #endif
+ } else {
+ if ((st->current_prot & L_PTE_RDONLY) == L_PTE_RDONLY)
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool is_prot_nx(struct pg_state *st)
+{
+ if (st->level < 4) {
+ if ((st->current_prot & PMD_SECT_XN) == PMD_SECT_XN)
+ return true;
+ } else {
+ if ((st->current_prot & L_PTE_XN) == L_PTE_XN)
+ return true;
+ }
+
+ return false;
+}
+
+static void note_prot_wx(struct pg_state *st, unsigned long addr)
+{
+ if (!st->check_wx)
+ return;
+ if (is_prot_ro(st))
+ return;
+ if (is_prot_nx(st))
+ return;
+
+ WARN_ONCE(1, "arm/mm: Found insecure W+X mapping at address %p/%pS\n",
+ (void *)st->start_address, (void *)st->start_address);
+
+ st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
+}
+
static void note_page(struct pg_state *st, unsigned long addr,
unsigned int level, u64 val, const char *domain)
{
@@ -244,6 +300,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
unsigned long delta;
if (st->current_prot) {
+ note_prot_wx(st, addr);
pt_dump_seq_printf(st->seq, "0x%08lx-0x%08lx ",
st->start_address, addr);
@@ -367,6 +424,7 @@ void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
struct pg_state st = {
.seq = m,
.marker = info->markers,
+ .check_wx = false,
};
walk_pgd(&st, info->mm, info->base_addr);
@@ -391,6 +449,26 @@ static void ptdump_initialize(void)
.base_addr = 0,
};
+void ptdump_check_wx(void)
+{
+ struct pg_state st = {
+ .seq = NULL,
+ .marker = (struct addr_marker[]) {
+ { 0, NULL},
+ { -1, NULL},
+ },
+ .check_wx = true,
+ };
+
+ walk_pgd(&st, &init_mm, 0);
+ note_page(&st, 0, 0, 0, NULL);
+ if (st.wx_pages)
+ pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n",
+ st.wx_pages);
+ else
+ pr_info("Checked W+X mappings: passed, no W+X pages found\n");
+}
+
static int ptdump_init(void)
{
ptdump_initialize();
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index a1f11a7..bd6f451 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -36,6 +36,7 @@
#include <asm/system_info.h>
#include <asm/tlb.h>
#include <asm/fixmap.h>
+#include <asm/ptdump.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -738,6 +739,7 @@ static int __mark_rodata_ro(void *unused)
void mark_rodata_ro(void)
{
stop_machine(__mark_rodata_ro, NULL, NULL);
+ debug_checkwx();
}
void set_kernel_text_rw(void)
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] thermal: mtk: Cleanup unused defines
From: Matthias Brugger @ 2017-12-01 10:43 UTC (permalink / raw)
To: linux-arm-kernel
The mtk_thermal has some defiens which are never used within the driver.
This patch delets them.
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
---
drivers/thermal/mtk_thermal.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
index 1e61c09153c9..c75661a3801a 100644
--- a/drivers/thermal/mtk_thermal.c
+++ b/drivers/thermal/mtk_thermal.c
@@ -32,15 +32,10 @@
#include <linux/types.h>
/* AUXADC Registers */
-#define AUXADC_CON0_V 0x000
-#define AUXADC_CON1_V 0x004
#define AUXADC_CON1_SET_V 0x008
#define AUXADC_CON1_CLR_V 0x00c
#define AUXADC_CON2_V 0x010
#define AUXADC_DATA(channel) (0x14 + (channel) * 4)
-#define AUXADC_MISC_V 0x094
-
-#define AUXADC_CON1_CHANNEL(x) BIT(x)
#define APMIXED_SYS_TS_CON1 0x604
@@ -158,8 +153,6 @@
/* The number of sensing points per bank */
#define MT2712_NUM_SENSORS_PER_ZONE 4
-#define THERMAL_NAME "mtk-thermal"
-
struct mtk_thermal;
struct thermal_bank_cfg {
@@ -765,7 +758,7 @@ static struct platform_driver mtk_thermal_driver = {
.probe = mtk_thermal_probe,
.remove = mtk_thermal_remove,
.driver = {
- .name = THERMAL_NAME,
+ .name = "mtk-thermal",
.of_match_table = mtk_thermal_of_match,
},
};
--
2.12.3
^ permalink raw reply related
* [kernel-hardening][PATCH 2/3] arm: mm: dump: make the page table dumping seq_file optional
From: jinb.park @ 2017-12-01 10:42 UTC (permalink / raw)
To: linux-arm-kernel
This patch makes the page table dumping seq_file optional.
It makes the page table dumping code usable for other cases.
This patch refers below commit of arm64.
(ae5d1cf358a5
("arm64: dump: Make the page table dumping seq_file optional"))
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
arch/arm/mm/dump.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 8dfe7c3..43a2bee 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -34,6 +34,18 @@
{ -1, NULL },
};
+#define pt_dump_seq_printf(m, fmt, args...) \
+({ \
+ if (m) \
+ seq_printf(m, fmt, ##args); \
+})
+
+#define pt_dump_seq_puts(m, fmt) \
+({ \
+ if (m) \
+ seq_printf(m, fmt); \
+})
+
struct pg_state {
struct seq_file *seq;
const struct addr_marker *marker;
@@ -210,7 +222,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits, size_t
s = bits->clear;
if (s)
- seq_printf(st->seq, " %s", s);
+ pt_dump_seq_printf(st->seq, " %s", s);
}
}
@@ -224,7 +236,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
st->level = level;
st->current_prot = prot;
st->current_domain = domain;
- seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
} else if (prot != st->current_prot || level != st->level ||
domain != st->current_domain ||
addr >= st->marker[1].start_address) {
@@ -232,7 +244,7 @@ static void note_page(struct pg_state *st, unsigned long addr,
unsigned long delta;
if (st->current_prot) {
- seq_printf(st->seq, "0x%08lx-0x%08lx ",
+ pt_dump_seq_printf(st->seq, "0x%08lx-0x%08lx ",
st->start_address, addr);
delta = (addr - st->start_address) >> 10;
@@ -240,17 +252,19 @@ static void note_page(struct pg_state *st, unsigned long addr,
delta >>= 10;
unit++;
}
- seq_printf(st->seq, "%9lu%c", delta, *unit);
+ pt_dump_seq_printf(st->seq, "%9lu%c", delta, *unit);
if (st->current_domain)
- seq_printf(st->seq, " %s", st->current_domain);
+ pt_dump_seq_printf(st->seq, " %s",
+ st->current_domain);
if (pg_level[st->level].bits)
dump_prot(st, pg_level[st->level].bits, pg_level[st->level].num);
- seq_printf(st->seq, "\n");
+ pt_dump_seq_printf(st->seq, "\n");
}
if (addr >= st->marker[1].start_address) {
st->marker++;
- seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ pt_dump_seq_printf(st->seq, "---[ %s ]---\n",
+ st->marker->name);
}
st->start_address = addr;
st->current_prot = prot;
--
1.9.1
^ permalink raw reply related
* [PATCH v3 0/5] ACPI: DMA ranges management
From: Lorenzo Pieralisi @ 2017-12-01 10:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL85gmDkrwuYPTyUn_cw1bQL2y9D65z2zJe3e79qjifN5Q_7-g@mail.gmail.com>
On Thu, Nov 30, 2017 at 04:43:00PM -0800, Feng Kan wrote:
> On Wed, Nov 29, 2017 at 11:28 PM, Feng Kan <fkan@apm.com> wrote:
> > On Thu, Aug 3, 2017 at 5:32 AM, Lorenzo Pieralisi
> > <lorenzo.pieralisi@arm.com> wrote:
> >> This patch series is v3 of a previous posting:
> >>
> >> v2->v3:
> >> - Fixed DMA masks computation
> >> - Fixed size computation overflow in acpi_dma_get_range()
> >>
> >> v1->v2:
> >> - Reworked acpi_dma_get_range() flow and logs
> >> - Added IORT named component address limits
> >> - Renamed acpi_dev_get_resources() helper function
> >> - Rebased against v4.13-rc3
> >>
> >> v2: http://lkml.kernel.org/r/20170731152323.32488-1-lorenzo.pieralisi at arm.com
> >> v1: http://lkml.kernel.org/r/20170720144517.32529-1-lorenzo.pieralisi at arm.com
> >>
> >> -- Original cover letter --
> >>
> >> As reported in:
> >>
> >> http://lkml.kernel.org/r/CAL85gmA_SSCwM80TKdkZqEe+S1beWzDEvdki1kpkmUTDRmSP7g at mail.gmail.com
> >>
> >> the bus connecting devices to an IOMMU bus can be smaller in size than
> >> the IOMMU input address bits which results in devices DMA HW bugs in
> >> particular related to IOVA allocation (ie chopping of higher address
> >> bits owing to system bus HW capabilities mismatch with the IOMMU).
> >>
> >> Fortunately this problem can be solved through an already present but never
> >> used ACPI 6.2 firmware bindings (ie _DMA object) allowing to define the DMA
> >> window for a specific bus in ACPI and therefore all upstream devices
> >> connected to it.
> >>
> >> This small patch series enables _DMA parsing in ACPI core code and
> >> use it in ACPI IORT code in order to detect DMA ranges for devices and
> >> update their data structures to make them work with their related DMA
> >> addressing restrictions.
> >>
> >> Cc: Will Deacon <will.deacon@arm.com>
> >> Cc: Hanjun Guo <hanjun.guo@linaro.org>
> >> Cc: Feng Kan <fkan@apm.com>
> >> Cc: Jon Masters <jcm@redhat.com>
> >> Cc: Robert Moore <robert.moore@intel.com>
> >> Cc: Robin Murphy <robin.murphy@arm.com>
> >> Cc: Zhang Rui <rui.zhang@intel.com>
> >> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
> >>
> >> Lorenzo Pieralisi (5):
> >> ACPICA: resource_mgr: Allow _DMA method in walk resources
> >> ACPI: Make acpi_dev_get_resources() method agnostic
> >> ACPI: Introduce DMA ranges parsing
> >> ACPI: Make acpi_dma_configure() DMA regions aware
> >> ACPI/IORT: Add IORT named component memory address limits
> >>
> >> drivers/acpi/acpica/rsxface.c | 7 ++--
> >> drivers/acpi/arm64/iort.c | 57 ++++++++++++++++++++++++++-
> >> drivers/acpi/resource.c | 82 +++++++++++++++++++++++++++++---------
> >> drivers/acpi/scan.c | 91 +++++++++++++++++++++++++++++++++++++++----
> >> include/acpi/acnames.h | 1 +
> >> include/acpi/acpi_bus.h | 2 +
> >> include/linux/acpi.h | 8 ++++
> >> include/linux/acpi_iort.h | 5 ++-
> >> 8 files changed, 219 insertions(+), 34 deletions(-)
> >>
> >> --
> >> 2.10.0
> >>
> > Lorenzo:
> >
> > A network driver can use pci_set_dma_mask or its like to override what
> > is done with this patch here.
> > Which would result in iova allocation greater than the original _DMA
> > aperture. Should we force
> > the dma_set_mask to not change if an existing mask is already set?
>
> Let me clarify the question some more, in our system the IOMMU supports only
> 42 bits of address. With your _DMA aperture patch, the initial dma_mask and
> coherent_mask are correctly set by the code. However, the device driver can
> set the dma_mask and coherent mask at a later point which over writes the
> initial setting by your code. In which case, once the iova is exhausted with the
> 32 bit address, it will start seeking more iova address via the
> dma_limit. In this
> case it would fail my system since the iommu.aperture_end is that of 48 bits
> as derived from ias field in the SMMU.
>
> Should the dma_limit be the smallest of driver->dma_mask, iommu.aperture_end and
> your _DMA aperture size via ACPI table? Rather than just the
> driver->dma_mask and
> iommu.aperture_end. This will ensure the smallest/correct aperture is used.
IIUC Nate already reported this issue - I will sync with Robin to
check the status of this thread:
https://marc.info/?l=linux-acpi&m=150108156230455&w=2
Thanks,
Lorenzo
^ permalink raw reply
* [kernel-hardening][PATCH 1/3] arm: mm: dump: make page table dumping reusable
From: jinb.park @ 2017-12-01 10:39 UTC (permalink / raw)
To: linux-arm-kernel
This patch refactors the arm page table dumping code,
so multiple tables may be registered with the framework.
This patch refers below commits of arm64.
(4674fdb9f149 ("arm64: mm: dump: make page table dumping reusable"))
(4ddb9bf83349 ("arm64: dump: Make ptdump debugfs a separate option"))
Signed-off-by: Jinbum Park <jinb.park7@gmail.com>
---
arch/arm/Kconfig.debug | 6 +++-
arch/arm/include/asm/ptdump.h | 48 ++++++++++++++++++++++++++++++++
arch/arm/mm/Makefile | 3 +-
arch/arm/mm/dump.c | 65 +++++++++++++++++++------------------------
arch/arm/mm/ptdump_debugfs.c | 34 ++++++++++++++++++++++
5 files changed, 117 insertions(+), 39 deletions(-)
create mode 100644 arch/arm/include/asm/ptdump.h
create mode 100644 arch/arm/mm/ptdump_debugfs.c
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 17685e1..e7b94db 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -3,10 +3,14 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config ARM_PTDUMP
+config ARM_PTDUMP_CORE
+ def_bool n
+
+config ARM_PTDUMP_DEBUGFS
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
depends on MMU
+ select ARM_PTDUMP_CORE
select DEBUG_FS
---help---
Say Y here if you want to show the kernel pagetable layout in a
diff --git a/arch/arm/include/asm/ptdump.h b/arch/arm/include/asm/ptdump.h
new file mode 100644
index 0000000..3a6c0b7
--- /dev/null
+++ b/arch/arm/include/asm/ptdump.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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/>.
+ */
+#ifndef __ASM_PTDUMP_H
+#define __ASM_PTDUMP_H
+
+#ifdef CONFIG_ARM_PTDUMP_CORE
+
+#include <linux/mm_types.h>
+#include <linux/seq_file.h>
+
+struct addr_marker {
+ unsigned long start_address;
+ char *name;
+};
+
+struct ptdump_info {
+ struct mm_struct *mm;
+ const struct addr_marker *markers;
+ unsigned long base_addr;
+};
+
+void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
+#ifdef CONFIG_ARM_PTDUMP_DEBUGFS
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
+#else
+static inline int ptdump_debugfs_register(struct ptdump_info *info,
+ const char *name)
+{
+ return 0;
+}
+#endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
+
+#endif /* CONFIG_ARM_PTDUMP_CORE */
+
+#endif /* __ASM_PTDUMP_H */
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 01bcc33..28be5f4 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -13,7 +13,8 @@ obj-y += nommu.o
obj-$(CONFIG_ARM_MPU) += pmsa-v7.o
endif
-obj-$(CONFIG_ARM_PTDUMP) += dump.o
+obj-$(CONFIG_ARM_PTDUMP_CORE) += dump.o
+obj-$(CONFIG_ARM_PTDUMP_DEBUGFS) += ptdump_debugfs.o
obj-$(CONFIG_MODULES) += proc-syms.o
obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index fc3b440..8dfe7c3 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -21,11 +21,7 @@
#include <asm/fixmap.h>
#include <asm/memory.h>
#include <asm/pgtable.h>
-
-struct addr_marker {
- unsigned long start_address;
- const char *name;
-};
+#include <asm/ptdump.h>
static struct addr_marker address_markers[] = {
{ MODULES_VADDR, "Modules" },
@@ -335,50 +331,36 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
}
}
-static void walk_pgd(struct seq_file *m)
+static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
+ unsigned long start)
{
- pgd_t *pgd = swapper_pg_dir;
- struct pg_state st;
- unsigned long addr;
+ pgd_t *pgd = pgd_offset(mm, 0UL);
unsigned i;
-
- memset(&st, 0, sizeof(st));
- st.seq = m;
- st.marker = address_markers;
+ unsigned long addr;
for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
- addr = i * PGDIR_SIZE;
+ addr = start + i * PGDIR_SIZE;
if (!pgd_none(*pgd)) {
- walk_pud(&st, pgd, addr);
+ walk_pud(st, pgd, addr);
} else {
- note_page(&st, addr, 1, pgd_val(*pgd), NULL);
+ note_page(st, addr, 1, pgd_val(*pgd), NULL);
}
}
-
- note_page(&st, 0, 0, 0, NULL);
}
-static int ptdump_show(struct seq_file *m, void *v)
+void ptdump_walk_pgd(struct seq_file *m, struct ptdump_info *info)
{
- walk_pgd(m);
- return 0;
-}
+ struct pg_state st = {
+ .seq = m,
+ .marker = info->markers,
+ };
-static int ptdump_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ptdump_show, NULL);
+ walk_pgd(&st, info->mm, info->base_addr);
+ note_page(&st, 0, 0, 0, NULL);
}
-static const struct file_operations ptdump_fops = {
- .open = ptdump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int ptdump_init(void)
+static void ptdump_initialize(void)
{
- struct dentry *pe;
unsigned i, j;
for (i = 0; i < ARRAY_SIZE(pg_level); i++)
@@ -387,9 +369,18 @@ static int ptdump_init(void)
pg_level[i].mask |= pg_level[i].bits[j].mask;
address_markers[2].start_address = VMALLOC_START;
+}
- pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
- &ptdump_fops);
- return pe ? 0 : -ENOMEM;
+static struct ptdump_info kernel_ptdump_info = {
+ .mm = &init_mm,
+ .markers = address_markers,
+ .base_addr = 0,
+};
+
+static int ptdump_init(void)
+{
+ ptdump_initialize();
+ return ptdump_debugfs_register(&kernel_ptdump_info,
+ "kernel_page_tables");
}
__initcall(ptdump_init);
diff --git a/arch/arm/mm/ptdump_debugfs.c b/arch/arm/mm/ptdump_debugfs.c
new file mode 100644
index 0000000..be8d87b
--- /dev/null
+++ b/arch/arm/mm/ptdump_debugfs.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptdump.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+ struct ptdump_info *info = m->private;
+
+ ptdump_walk_pgd(m, info);
+ return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ptdump_show, inode->i_private);
+}
+
+static const struct file_operations ptdump_fops = {
+ .open = ptdump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
+{
+ struct dentry *pe;
+
+ pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
+ return pe ? 0 : -ENOMEM;
+
+}
--
1.9.1
^ permalink raw reply related
* [kernel-hardening][PATCH 0/3] arm: Makes ptdump resuable and add WX page checking
From: jinb.park @ 2017-12-01 10:38 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
Page table dumping code for arm64-x86 is reusable,
and they have function for WX page checking.
But arm doesn't have that.
This path series are to makes ptdump reusable,
and add WX page checking for arm.
This is heavily based on arm64 version.
Jinbum Park (3):
arm: mm: dump: make page table dumping reusable
arm: mm: dump: make the page table dumping seq_file optional
arm: mm: dump: add checking for writable and executable pages
arch/arm/Kconfig.debug | 33 +++++++-
arch/arm/include/asm/ptdump.h | 56 ++++++++++++++
arch/arm/mm/Makefile | 3 +-
arch/arm/mm/dump.c | 171 +++++++++++++++++++++++++++++++-----------
arch/arm/mm/init.c | 2 +
arch/arm/mm/ptdump_debugfs.c | 34 +++++++++
6 files changed, 253 insertions(+), 46 deletions(-)
create mode 100644 arch/arm/include/asm/ptdump.h
create mode 100644 arch/arm/mm/ptdump_debugfs.c
--
1.9.1
^ permalink raw reply
* [PATCH v3 4/4] DTS: Pandora: fix panel compatibility string
From: Tomi Valkeinen @ 2017-12-01 10:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0324FA0E-F06A-41F1-84AD-5BC72F6B6BFF@goldelico.com>
On 01/12/17 11:48, H. Nikolaus Schaller wrote:
> Just a note: there is no toppoly->tpo change for *this* panel and
> Pandora board. Just omapdss removal.
>
> The GTA04 needs a toppoly->tpo change but no omapdss, removal.
>
> So they solve different problems and are independent of each other.
>
> GTA04: change vendor string
> Pandora: remove omapdss, prefix
Oh, right, I totally missed that. I thought they were changes to the
same file...
In that case, Tony, can you pick this one as a fix? I'll pick the
toppoly->tpo patch and merge via drm tree, if you give the ack.
For this:
Acked-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Tomi
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply
* [PATCH 5/5] mtd: nand: add ->exec_op() implementation
From: Miquel RAYNAL @ 2017-12-01 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171201105053.25af2267@bbrezillon>
Hi Boris,
On Fri, 1 Dec 2017 10:50:53 +0100
Boris Brezillon <boris.brezillon@free-electrons.com> wrote:
> Hi Miquel,
>
> On Thu, 30 Nov 2017 23:25:38 +0100
> Miquel RAYNAL <miquel.raynal@free-electrons.com> wrote:
>
> > > > diff --git a/drivers/mtd/nand/nand_base.c
> > > > b/drivers/mtd/nand/nand_base.c index 52965a8aeb2c..46bf31aff909
> > > > 100644 --- a/drivers/mtd/nand/nand_base.c
> > > > +++ b/drivers/mtd/nand/nand_base.c
> > > > @@ -689,6 +689,59 @@ static void nand_wait_status_ready(struct
> > > > mtd_info *mtd, unsigned long timeo) };
> > > >
> > > > /**
> > > > + * nand_soft_waitrdy - Read the status waiting for it to be
> > > > ready
> > > > + * @chip: NAND chip structure
> > > > + * @timeout_ms: Timeout in ms
> > > > + *
> > > > + * Poll the status using ->exec_op() until it is ready unless
> > > > it takes too
> > > > + * much time.
> > > > + *
> > > > + * This helper is intended to be used by drivers without R/B
> > > > pin available to
> > > > + * poll for the chip status until ready and may be called at
> > > > any time in the
> > > > + * middle of any set of instruction. The READ_STATUS just need
> > > > to ask a single
> > > > + * time for it and then any read will return the status. Once
> > > > the READ_STATUS
> > > > + * cycles are done, the function will send a READ0 command to
> > > > cancel the
> > > > + * "READ_STATUS state" and let the normal flow of operation to
> > > > continue.
> > > > + *
> > > > + * This helper *cannot* send a WAITRDY command or ->exec_op()
> > > > implementations
> > >
> > > ^ instruction
> > >
> > > > + * using it will enter an infinite loop.
> > >
> > > Hm, not sure why this would be the case, but okay. Maybe you
> > > should move this comment outside the kernel doc header, since
> > > this is an implementation detail, not something the caller/user
> > > should be aware of.
> >
> > Right.
> >
> > >
> > > There's another important aspect to mention here: this function
> > > can only be called from an ->exec_op() implementation if this
> > > implementation is re-entrant.
> >
> > I do not agree with this statement: this function can be called
> > from an ->exec_op() implementation even if it is not reentrant as
> > long as it does not send a WAITRDY instruction itself. No?
>
> If the ->exec_op() implementation is not re-entrant, no,
> nand_soft_waitrdy() can't be called from ->exec_op(), because then
> you will re-enter ->exec_op() to execute the read_status_op(), and
> BOOM!
>
> >
> > Or maybe you wanted to point that the entire ->exec_op()
> > implementation must be reentrant in order to use this function in
> > it?
>
> Yes, what did you understand?
Ok, I think I misunderstood the "if this implementation is re-entrant".
The implementation you were referring to was ->exec_op()'s
implementation, not nand_soft_waitrdy()'s.
>
> >
> > >
> > > > + *
> > > > + * Return 0 if the NAND chip is ready, a negative error
> > > > otherwise.
> > > > + */
> > > > +int nand_soft_waitrdy(struct nand_chip *chip, unsigned long
> > > > timeout_ms) +{
> > > > + u8 status = 0;
> > > > + int ret;
> > > > +
> > > > + if (!chip->exec_op)
> > > > + return -ENOTSUPP;
> > > > +
> > > > + ret = nand_status_op(chip, NULL);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
> > > > + do {
> > > > + ret = nand_read_data_op(chip, &status,
> > > > sizeof(status), true);
> > > > + if (ret)
> > > > + break;
> > > > +
> > > > + if (status & NAND_STATUS_READY)
> > > > + break;
> > > > +
> > > > + udelay(100);
> > >
> > > Sounds a bit high, especially for a read page which takes around
> > > 20us.
> >
> > Well, this value is arbitrary but greping for NAND_OP_WAIT_RDY
> > tells us the different timeouts with which this function is usually
> > called, to get an idea of the possible wait periods: tR, tBERS,
> > tFEAT, tPROG, tRST.
> >
> > While a tR_max is 200us, a tRST_max is 250000us. That is why I
> > choose 100us as period, which I found somehow well tuned for every
> > timeout.
>
> A timeout is different from a typical execution time. The timeout is
> here as a boundary to detect when the device/controller is not
> responding, so if you poll the status at the periodicity of the
> timeout, you're likely to wait much more than you should have.
>
> > But
> > if you think most of the time the delay will be smaller, I will
> > update the value to repeat the operation every 20us.
>
> Well, either you do something smart that calculates a polling period
> based on the timeout val (timeout / ratio), or you pick something
> close to the lowest typical value. So, in our case, something like
> 10us, which should not be far from the typical tR value on most NANDs.
For the sake of simplicity, I will then use 10us polling period here.
Thanks,
Miqu?l
^ permalink raw reply
* [RFC PATCH 1/3] dt-bindings: pinctrl: sunxi: document new generic binding
From: Linus Walleij @ 2017-12-01 9:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0c8051e6-5d8c-32d6-97e4-11c2283da5b4@arm.com>
On Fri, Nov 24, 2017 at 6:19 PM, Andre Przywara <andre.przywara@arm.com> wrote:
> Conceptually I consider the DT being
> part of the firmware,
As it is a subset of open firmware it is obviously firmware.
> so one trust level above the kernel.
We are several kernel developers who don't trust firmware one
bit. Several disasters in ACPI has made me ever more convinced
that firmware should be trusted less than kernel code.
But this is all very academic.
>> Also, device tree bindings are not documentation for how to write a
>> driver. They are not a replacement for hardware documentation. Nobody
>> should be expected to be able to write an OS driver solely based on a
>> device tree binding. Device tree bindings are more of a configuration
>> interface specification for OS drivers.
>
> Yes, but together with the hardware docs you should be able to write a
> driver. And here you can't, because you are missing the strings. So a
> BSD developer has to look at Linux code.
This is a fair point. It appears in several drivers.
BSD or even Windows (would they use DT) would have to sit in the
back seat just like Linux has been doing for years when it comes
to the hopeless Windowsisms in the x86 BIOSes. I suspect some
Windows on ARM is already experiencing this, but in the ACPI world,
where, incidentally, the servers were being deployed for Linux first
and Windows had to follow their example. I bet they have been
swearing a lot in Redmond about that.
In general it's one of these areas where we can not be utopian about the
hardware descriptions, just fail gracefully in different ways.
I usually try to keep the IETF motto "rough consensus and running
code" in mind. I don't know if it helps in this discussion though.
>> So that's about 40% of the kernel image. Code really is no good without
>> data to process.
>
> But how much of this is SoC specific configuration data? How much is it
> in x86? Yes, historically we had and have a lot of configuration data in
> ARM kernels. But that doesn't mean that we have to continue with this or
> even increase the share.
What people have been doing is trying to have better Kconfig setups
and compile it out by doing kernel modules. It is a bit hopeless with
pin controllers: almost all of them have to be built in. And if they come
with a lot of data, yeah there you have a real good point.
It would be sad if the ARMv7 multiboot or Aarch64 kernel just grows
so that we can't use it but have to go back to shipping board-specific
kernels with a huge bunch of stuff compiled out.
I was hoping Moore's law would save us here :/
An option that has been discussed is better used of __initdata
and similar tags, especially with built-in drivers. Sadly, this is
hurt by another snag: the compiler or linker file or whatever it is,
is preventing us from discarding any strings from the kernel.
And pin controllers tend to stack up a lot of these.
This is really sucky and something we should solve in general.
I'm not smart enough to tackle any of these problems myself, just
to see them and "Oh that's bad. Very bad."
>> The majority of the improvements over the years have been achieved by
>> moving drivers out of arch/arm and moving board files to DT. The goal
>> was never to get rid of all data.
>
> Sure, not all data. But if we have the relatively easy opportunity to
> avoid further addition of data, we should do it, I believe.
> This significantly reduces the amount of kernel code we need to add to
> support new SoCs.
This is the core of your argument as I perceive it: get rid of data
from the kernel, because it is growing wild. It is a valid cause. Just
has to be weighed with other stuff, like maintainability, debuggability,
maintainers viewpoint. ...
Yours,
Linus Walleij
^ permalink raw reply
* [PATCH 5/5] mtd: nand: add ->exec_op() implementation
From: Boris Brezillon @ 2017-12-01 9:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171130232538.140f17b1@xps13>
Hi Miquel,
On Thu, 30 Nov 2017 23:25:38 +0100
Miquel RAYNAL <miquel.raynal@free-electrons.com> wrote:
> > > diff --git a/drivers/mtd/nand/nand_base.c
> > > b/drivers/mtd/nand/nand_base.c index 52965a8aeb2c..46bf31aff909
> > > 100644 --- a/drivers/mtd/nand/nand_base.c
> > > +++ b/drivers/mtd/nand/nand_base.c
> > > @@ -689,6 +689,59 @@ static void nand_wait_status_ready(struct
> > > mtd_info *mtd, unsigned long timeo) };
> > >
> > > /**
> > > + * nand_soft_waitrdy - Read the status waiting for it to be ready
> > > + * @chip: NAND chip structure
> > > + * @timeout_ms: Timeout in ms
> > > + *
> > > + * Poll the status using ->exec_op() until it is ready unless it
> > > takes too
> > > + * much time.
> > > + *
> > > + * This helper is intended to be used by drivers without R/B pin
> > > available to
> > > + * poll for the chip status until ready and may be called at any
> > > time in the
> > > + * middle of any set of instruction. The READ_STATUS just need to
> > > ask a single
> > > + * time for it and then any read will return the status. Once the
> > > READ_STATUS
> > > + * cycles are done, the function will send a READ0 command to
> > > cancel the
> > > + * "READ_STATUS state" and let the normal flow of operation to
> > > continue.
> > > + *
> > > + * This helper *cannot* send a WAITRDY command or ->exec_op()
> > > implementations
> >
> > ^ instruction
> >
> > > + * using it will enter an infinite loop.
> >
> > Hm, not sure why this would be the case, but okay. Maybe you should
> > move this comment outside the kernel doc header, since this is an
> > implementation detail, not something the caller/user should be aware
> > of.
>
> Right.
>
> >
> > There's another important aspect to mention here: this function can
> > only be called from an ->exec_op() implementation if this
> > implementation is re-entrant.
>
> I do not agree with this statement: this function can be called from an
> ->exec_op() implementation even if it is not reentrant as long as it
> does not send a WAITRDY instruction itself. No?
If the ->exec_op() implementation is not re-entrant, no,
nand_soft_waitrdy() can't be called from ->exec_op(), because then
you will re-enter ->exec_op() to execute the read_status_op(), and BOOM!
>
> Or maybe you wanted to point that the entire ->exec_op()
> implementation must be reentrant in order to use this function in it?
Yes, what did you understand?
>
> >
> > > + *
> > > + * Return 0 if the NAND chip is ready, a negative error otherwise.
> > > + */
> > > +int nand_soft_waitrdy(struct nand_chip *chip, unsigned long
> > > timeout_ms) +{
> > > + u8 status = 0;
> > > + int ret;
> > > +
> > > + if (!chip->exec_op)
> > > + return -ENOTSUPP;
> > > +
> > > + ret = nand_status_op(chip, NULL);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + timeout_ms = jiffies + msecs_to_jiffies(timeout_ms);
> > > + do {
> > > + ret = nand_read_data_op(chip, &status,
> > > sizeof(status), true);
> > > + if (ret)
> > > + break;
> > > +
> > > + if (status & NAND_STATUS_READY)
> > > + break;
> > > +
> > > + udelay(100);
> >
> > Sounds a bit high, especially for a read page which takes around 20us.
>
> Well, this value is arbitrary but greping for NAND_OP_WAIT_RDY tells us
> the different timeouts with which this function is usually called, to
> get an idea of the possible wait periods: tR, tBERS, tFEAT, tPROG, tRST.
>
> While a tR_max is 200us, a tRST_max is 250000us. That is why I choose
> 100us as period, which I found somehow well tuned for every timeout.
A timeout is different from a typical execution time. The timeout is
here as a boundary to detect when the device/controller is not
responding, so if you poll the status at the periodicity of the
timeout, you're likely to wait much more than you should have.
> But
> if you think most of the time the delay will be smaller, I will update
> the value to repeat the operation every 20us.
Well, either you do something smart that calculates a polling period
based on the timeout val (timeout / ratio), or you pick something
close to the lowest typical value. So, in our case, something like
10us, which should not be far from the typical tR value on most NANDs.
Regards,
Boris
>
> >
> > > + } while (time_before(jiffies, timeout_ms));
> > > +
> > > + nand_exit_status_op(chip);
> > > +
> > > + if (ret)
> > > + return ret;
> > > +
> > > + return status & NAND_STATUS_READY ? 0 : -ETIMEDOUT;
> > > +};
> > > +EXPORT_SYMBOL_GPL(nand_soft_waitrdy);
> > > +
^ permalink raw reply
* [PATCH v3 4/4] DTS: Pandora: fix panel compatibility string
From: H. Nikolaus Schaller @ 2017-12-01 9:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6ca5f2ea-e725-9a9e-ac02-e16beca4a1a0@ti.com>
Hi Tomi,
> Am 01.12.2017 um 09:13 schrieb Tomi Valkeinen <tomi.valkeinen@ti.com>:
>
> On 01/12/17 00:06, Sebastian Reichel wrote:
>
>>>>> How about let's call it a "typo fix" then? :)
>>>>
>>>> Well, it is not really a typo.
>>>
>>> Well what if the stable people pick it into earlier stable series
>>> based on the word fix in the subject? That has happened before.
>>>
>>> I suggest you update the dts patches to use wording like
>>> "update compatible to use new naming" or something similar.
>>
>> Patch 4/4 is a Fix and should be applied to stable trees. "omapdss,"
>> prefix was never supposed to be in the DTS files, is not supposed to
>> be in there now and will break some time in the future.
>>
>> Explanation: The early init of omapdss adds the prefix at runtime,
>> so that the binding can use generic properties and the kernel can
>> use omapdss specific drivers until the generic ones can be used
>
> This is true, but the extra "omapdss" does not cause any issues at the
> moment, and the time when it causes issues is still many kernel versions
> in the future.
>
> But, yes, thinking about this, I agree, it's better to pick this one
> separately as a fix (after rebasing it on top of current maineline so
> that it doesn't depend on the toppoly name change), and leaving the
> toppoly->tpo change as a cleanup.
Just a note: there is no toppoly->tpo change for *this* panel and
Pandora board. Just omapdss removal.
The GTA04 needs a toppoly->tpo change but no omapdss, removal.
So they solve different problems and are independent of each other.
GTA04: change vendor string
Pandora: remove omapdss, prefix
BR and thanks,
Nikolaus
^ permalink raw reply
* [PATCH v4 4/6] ARM: dts: imx6qdl: Add Variscite DART-MX6 SoM support
From: Philippe Ombredanne @ 2017-12-01 9:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <118caa5c-6782-f4ca-443e-19d483171e01@baylibre.com>
Neil,
On Fri, Dec 1, 2017 at 10:19 AM, Neil Armstrong <narmstrong@baylibre.com> wrote:
> Hi Philippe,
>
> On 01/12/2017 10:02, Philippe Ombredanne wrote:
>> On Fri, Dec 1, 2017 at 9:54 AM, Neil Armstrong <narmstrong@baylibre.com> wrote:
>>> On 30/11/2017 01:39, Shawn Guo wrote:
>>>> On Wed, Nov 29, 2017 at 11:20:55AM +0100, Neil Armstrong wrote:
>>>>> This patch adds support for the Variscite DART-MX6 SoM with :
>>>>> - i.MX6 Quad or Dual Lite SoC
>>>>> - 1Gb/2Gb LPDDR2
>>>>> - 4-64 GB eMMC
>>>>> - Camera Interface
>>>>> - HDMI+CEC interface
>>>>> - LVDS / DSI / Parallel RGB interfaces
>>>>> - Ethernet RGMII interface
>>>>> - On-SoM Wi-Fi/Bluetooth with WiLink wl1835 SDIO Module
>>>>> - SD/MMC/SDIO interface
>>>>> - USB Host + USB OTG interface
>>>>> - I2C interfaces
>>>>> - SPI interfaces
>>>>> - PCI-Express 2.0 interface
>>>>> - on-SoM Audio Codec with HP/Line-In interfaces + DMIC interface
>>>>> - Digital Audio interface
>>>>> - S/PDIF interface
>>>>>
>>>>> Product website : http://www.variscite.com/products/system-on-module-som/cortex-a9/dart-mx6-cpu-freescale-imx6
>>>>>
>>>>> Support is handled with a SoM-centric dtsi exporting the default interfaces
>>>>> along the default pinmuxing to be enabled by the board dts file.
>>>>>
>>>>> Only board-independent devices like WiFi, eMMC or PMIC are enabled in the dtsi.
>>>>>
>>>>> Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
>>>>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>>>>
>>>> Looks pretty good. Only a couple of minor comments.
>>>>
>>>>> ---
>>>>> arch/arm/boot/dts/imx6qdl-var-dart.dtsi | 504 ++++++++++++++++++++++++++++++++
>>>>> 1 file changed, 504 insertions(+)
>>>>> create mode 100644 arch/arm/boot/dts/imx6qdl-var-dart.dtsi
>>>>>
>>>>> diff --git a/arch/arm/boot/dts/imx6qdl-var-dart.dtsi b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi
>>>>> new file mode 100644
>>>>> index 0000000..fd2520b
>>>>> --- /dev/null
>>>>> +++ b/arch/arm/boot/dts/imx6qdl-var-dart.dtsi
>>>>> @@ -0,0 +1,504 @@
>>>>> +/*
>>>>> + * Support for Variscite DART-MX6 Module
>>>>> + *
>>>>> + * Copyright 2017 BayLibre, SAS
>>>>> + * Author: Neil Armstrong <narmstrong@baylibre.com>
>>>>> + *
>>>>> + * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>>>> + */
>>
>> Should this be instead on the first line with a // comment style if
>> possible, right?
>
> I just saw this right now.
>
> Damn, I just sent a v5...
>
>>
>>>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>>
>> Thomas has sent a first doc patch [1] set and is working on an updated
>> version. Jonathan also wrote a nice background article on the topic
>> at LWN [2].
>>
>> Linus explained why he wants the // comment style and a first line
>> location on the list too.
>>
>> [1] https://marc.info/?l=linux-kernel&m=151051532322831&w=2
>> [2] https://lwn.net/SubscriberLink/739183/262749cbe307ddc7/
>>
Sorry for wrecking your workflow with a smallish comment related
comment and I am grateful that you consider this.
Thomas (tglx) is working on updated doc patches as soon as his real
time clock yields a few ticks for doc work...
The point is that Greg pushed already 10K+ file updates with proper
SPDX ids.... I chipped in a bit there and there are still eventually
60k+ files to go to have a uniform and simplified licensing
kernel-wide.
So, every little bit to help avoiding drift and regress is helpful.
Linus request for using // is to make this unambiguously greppable.
The selfish benefit to me is that eventually I will be able to send
to the trash my license scanner in the future [1] (we use it to help
cleanup the kernel FWIW) and replace this with a good' ole grep once
everyone on earth use clean and greppable licensing... The kernel is
setting the pace there for the whole FLOSS world and I hope this will
snow ball, but hope is not a strategy! Once the kernel is done, I will
have only more or less 100 billion+ file left to clean after that ;)
[1] https://github.com/nexB/scancode-toolkit
--
Cordially
Philippe Ombredanne
^ 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