* [PATCH v10 14/18] drivers/clocksource: timer-fsl-ftm: use common header for FlexTimer #defines
From: William Breathitt Gray @ 2019-04-02 6:30 UTC (permalink / raw)
To: gregkh
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, William Breathitt Gray,
robh+dt, tglx, fabrice.gasnier, esben, shawnguo, linux-kernel,
leoyang.li, knaack.h, akpm, linuxppc-dev, jic23
In-Reply-To: <cover.1554184734.git.vilhelm.gray@gmail.com>
From: Patrick Havelange <patrick.havelange@essensium.com>
Common #defines have been moved to "linux/fsl/ftm.h". Thus making use of
this file.
Also FTM_SC_CLK_SHIFT has been renamed to FTM_SC_CLK_MASK_SHIFT.
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/clocksource/timer-fsl-ftm.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/clocksource/timer-fsl-ftm.c b/drivers/clocksource/timer-fsl-ftm.c
index 846d18daf893..e1c34b2f53a5 100644
--- a/drivers/clocksource/timer-fsl-ftm.c
+++ b/drivers/clocksource/timer-fsl-ftm.c
@@ -19,20 +19,9 @@
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <linux/slab.h>
+#include <linux/fsl/ftm.h>
-#define FTM_SC 0x00
-#define FTM_SC_CLK_SHIFT 3
-#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
-#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
-#define FTM_SC_PS_MASK 0x7
-#define FTM_SC_TOIE BIT(6)
-#define FTM_SC_TOF BIT(7)
-
-#define FTM_CNT 0x04
-#define FTM_MOD 0x08
-#define FTM_CNTIN 0x4C
-
-#define FTM_PS_MAX 7
+#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT)
struct ftm_clock_device {
void __iomem *clksrc_base;
--
2.21.0
^ permalink raw reply related
* [PATCH v10 15/18] dt-bindings: counter: ftm-quaddec
From: William Breathitt Gray @ 2019-04-02 6:30 UTC (permalink / raw)
To: gregkh
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, William Breathitt Gray,
robh+dt, tglx, fabrice.gasnier, esben, shawnguo, linux-kernel,
leoyang.li, knaack.h, akpm, linuxppc-dev, jic23
In-Reply-To: <cover.1554184734.git.vilhelm.gray@gmail.com>
From: Patrick Havelange <patrick.havelange@essensium.com>
FlexTimer quadrature decoder driver.
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
.../bindings/counter/ftm-quaddec.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/counter/ftm-quaddec.txt
diff --git a/Documentation/devicetree/bindings/counter/ftm-quaddec.txt b/Documentation/devicetree/bindings/counter/ftm-quaddec.txt
new file mode 100644
index 000000000000..4d18cd722074
--- /dev/null
+++ b/Documentation/devicetree/bindings/counter/ftm-quaddec.txt
@@ -0,0 +1,18 @@
+FlexTimer Quadrature decoder counter
+
+This driver exposes a simple counter for the quadrature decoder mode.
+
+Required properties:
+- compatible: Must be "fsl,ftm-quaddec".
+- reg: Must be set to the memory region of the flextimer.
+
+Optional property:
+- big-endian: Access the device registers in big-endian mode.
+
+Example:
+ counter0: counter@29d0000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
--
2.21.0
^ permalink raw reply related
* [PATCH v10 16/18] counter: add FlexTimer Module Quadrature decoder counter driver
From: William Breathitt Gray @ 2019-04-02 6:30 UTC (permalink / raw)
To: gregkh
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, William Breathitt Gray,
robh+dt, tglx, fabrice.gasnier, esben, shawnguo, linux-kernel,
leoyang.li, knaack.h, akpm, linuxppc-dev, jic23
In-Reply-To: <cover.1554184734.git.vilhelm.gray@gmail.com>
From: Patrick Havelange <patrick.havelange@essensium.com>
This driver exposes the counter for the quadrature decoder of the
FlexTimer Module, present in the LS1021A soc.
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
drivers/counter/Kconfig | 9 +
drivers/counter/Makefile | 1 +
drivers/counter/ftm-quaddec.c | 356 ++++++++++++++++++++++++++++++++++
3 files changed, 366 insertions(+)
create mode 100644 drivers/counter/ftm-quaddec.c
diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig
index 87c491a19c63..233ac305d878 100644
--- a/drivers/counter/Kconfig
+++ b/drivers/counter/Kconfig
@@ -48,4 +48,13 @@ config STM32_LPTIMER_CNT
To compile this driver as a module, choose M here: the
module will be called stm32-lptimer-cnt.
+config FTM_QUADDEC
+ tristate "Flex Timer Module Quadrature decoder driver"
+ help
+ Select this option to enable the Flex Timer Quadrature decoder
+ driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ftm-quaddec.
+
endif # COUNTER
diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile
index 5589976d37f8..0c9e622a6bea 100644
--- a/drivers/counter/Makefile
+++ b/drivers/counter/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_COUNTER) += counter.o
obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
+obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o
diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c
new file mode 100644
index 000000000000..c83c8875bf82
--- /dev/null
+++ b/drivers/counter/ftm-quaddec.c
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Flex Timer Module Quadrature decoder
+ *
+ * This module implements a driver for decoding the FTM quadrature
+ * of ex. a LS1021A
+ */
+
+#include <linux/fsl/ftm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/counter.h>
+#include <linux/bitfield.h>
+
+#define FTM_FIELD_UPDATE(ftm, offset, mask, val) \
+ ({ \
+ uint32_t flags; \
+ ftm_read(ftm, offset, &flags); \
+ flags &= ~mask; \
+ flags |= FIELD_PREP(mask, val); \
+ ftm_write(ftm, offset, flags); \
+ })
+
+struct ftm_quaddec {
+ struct counter_device counter;
+ struct platform_device *pdev;
+ void __iomem *ftm_base;
+ bool big_endian;
+ struct mutex ftm_quaddec_mutex;
+};
+
+static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t *data)
+{
+ if (ftm->big_endian)
+ *data = ioread32be(ftm->ftm_base + offset);
+ else
+ *data = ioread32(ftm->ftm_base + offset);
+}
+
+static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t data)
+{
+ if (ftm->big_endian)
+ iowrite32be(data, ftm->ftm_base + offset);
+ else
+ iowrite32(data, ftm->ftm_base + offset);
+}
+
+/* Hold mutex before modifying write protection state */
+static void ftm_clear_write_protection(struct ftm_quaddec *ftm)
+{
+ uint32_t flag;
+
+ /* First see if it is enabled */
+ ftm_read(ftm, FTM_FMS, &flag);
+
+ if (flag & FTM_FMS_WPEN)
+ FTM_FIELD_UPDATE(ftm, FTM_MODE, FTM_MODE_WPDIS, 1);
+}
+
+static void ftm_set_write_protection(struct ftm_quaddec *ftm)
+{
+ FTM_FIELD_UPDATE(ftm, FTM_FMS, FTM_FMS_WPEN, 1);
+}
+
+static void ftm_reset_counter(struct ftm_quaddec *ftm)
+{
+ /* Reset hardware counter to CNTIN */
+ ftm_write(ftm, FTM_CNT, 0x0);
+}
+
+static void ftm_quaddec_init(struct ftm_quaddec *ftm)
+{
+ ftm_clear_write_protection(ftm);
+
+ /*
+ * Do not write in the region from the CNTIN register through the
+ * PWMLOAD register when FTMEN = 0.
+ * Also reset other fields to zero
+ */
+ ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN);
+ ftm_write(ftm, FTM_CNTIN, 0x0000);
+ ftm_write(ftm, FTM_MOD, 0xffff);
+ ftm_write(ftm, FTM_CNT, 0x0);
+ /* Set prescaler, reset other fields to zero */
+ ftm_write(ftm, FTM_SC, FTM_SC_PS_1);
+
+ /* Select quad mode, reset other fields to zero */
+ ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN);
+
+ /* Unused features and reset to default section */
+ ftm_write(ftm, FTM_POL, 0x0);
+ ftm_write(ftm, FTM_FLTCTRL, 0x0);
+ ftm_write(ftm, FTM_SYNCONF, 0x0);
+ ftm_write(ftm, FTM_SYNC, 0xffff);
+
+ /* Lock the FTM */
+ ftm_set_write_protection(ftm);
+}
+
+static void ftm_quaddec_disable(struct ftm_quaddec *ftm)
+{
+ ftm_clear_write_protection(ftm);
+ ftm_write(ftm, FTM_MODE, 0);
+ ftm_write(ftm, FTM_QDCTRL, 0);
+ /*
+ * This is enough to disable the counter. No clock has been
+ * selected by writing to FTM_SC in init()
+ */
+ ftm_set_write_protection(ftm);
+}
+
+static int ftm_quaddec_get_prescaler(struct counter_device *counter,
+ struct counter_count *count,
+ size_t *cnt_mode)
+{
+ struct ftm_quaddec *ftm = counter->priv;
+ uint32_t scflags;
+
+ ftm_read(ftm, FTM_SC, &scflags);
+
+ *cnt_mode = FIELD_GET(FTM_SC_PS_MASK, scflags);
+
+ return 0;
+}
+
+static int ftm_quaddec_set_prescaler(struct counter_device *counter,
+ struct counter_count *count,
+ size_t cnt_mode)
+{
+ struct ftm_quaddec *ftm = counter->priv;
+
+ mutex_lock(&ftm->ftm_quaddec_mutex);
+
+ ftm_clear_write_protection(ftm);
+ FTM_FIELD_UPDATE(ftm, FTM_SC, FTM_SC_PS_MASK, cnt_mode);
+ ftm_set_write_protection(ftm);
+
+ /* Also resets the counter as it is undefined anyway now */
+ ftm_reset_counter(ftm);
+
+ mutex_unlock(&ftm->ftm_quaddec_mutex);
+ return 0;
+}
+
+static const char * const ftm_quaddec_prescaler[] = {
+ "1", "2", "4", "8", "16", "32", "64", "128"
+};
+
+static struct counter_count_enum_ext ftm_quaddec_prescaler_enum = {
+ .items = ftm_quaddec_prescaler,
+ .num_items = ARRAY_SIZE(ftm_quaddec_prescaler),
+ .get = ftm_quaddec_get_prescaler,
+ .set = ftm_quaddec_set_prescaler
+};
+
+enum ftm_quaddec_synapse_action {
+ FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES,
+};
+
+static enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
+ [FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES] =
+ COUNTER_SYNAPSE_ACTION_BOTH_EDGES
+};
+
+enum ftm_quaddec_count_function {
+ FTM_QUADDEC_COUNT_ENCODER_MODE_1,
+};
+
+static const enum counter_count_function ftm_quaddec_count_functions[] = {
+ [FTM_QUADDEC_COUNT_ENCODER_MODE_1] =
+ COUNTER_COUNT_FUNCTION_QUADRATURE_X4
+};
+
+static int ftm_quaddec_count_read(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_count_read_value *val)
+{
+ struct ftm_quaddec *const ftm = counter->priv;
+ uint32_t cntval;
+
+ ftm_read(ftm, FTM_CNT, &cntval);
+
+ counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval);
+
+ return 0;
+}
+
+static int ftm_quaddec_count_write(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_count_write_value *val)
+{
+ struct ftm_quaddec *const ftm = counter->priv;
+ u32 cnt;
+ int err;
+
+ err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
+ if (err)
+ return err;
+
+ if (cnt != 0) {
+ dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n");
+ return -EINVAL;
+ }
+
+ ftm_reset_counter(ftm);
+
+ return 0;
+}
+
+static int ftm_quaddec_count_function_get(struct counter_device *counter,
+ struct counter_count *count,
+ size_t *function)
+{
+ *function = FTM_QUADDEC_COUNT_ENCODER_MODE_1;
+
+ return 0;
+}
+
+static int ftm_quaddec_action_get(struct counter_device *counter,
+ struct counter_count *count,
+ struct counter_synapse *synapse,
+ size_t *action)
+{
+ *action = FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES;
+
+ return 0;
+}
+
+static const struct counter_ops ftm_quaddec_cnt_ops = {
+ .count_read = ftm_quaddec_count_read,
+ .count_write = ftm_quaddec_count_write,
+ .function_get = ftm_quaddec_count_function_get,
+ .action_get = ftm_quaddec_action_get,
+};
+
+static struct counter_signal ftm_quaddec_signals[] = {
+ {
+ .id = 0,
+ .name = "Channel 1 Phase A"
+ },
+ {
+ .id = 1,
+ .name = "Channel 1 Phase B"
+ }
+};
+
+static struct counter_synapse ftm_quaddec_count_synapses[] = {
+ {
+ .actions_list = ftm_quaddec_synapse_actions,
+ .num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions),
+ .signal = &ftm_quaddec_signals[0]
+ },
+ {
+ .actions_list = ftm_quaddec_synapse_actions,
+ .num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions),
+ .signal = &ftm_quaddec_signals[1]
+ }
+};
+
+static const struct counter_count_ext ftm_quaddec_count_ext[] = {
+ COUNTER_COUNT_ENUM("prescaler", &ftm_quaddec_prescaler_enum),
+ COUNTER_COUNT_ENUM_AVAILABLE("prescaler", &ftm_quaddec_prescaler_enum),
+};
+
+static struct counter_count ftm_quaddec_counts = {
+ .id = 0,
+ .name = "Channel 1 Count",
+ .functions_list = ftm_quaddec_count_functions,
+ .num_functions = ARRAY_SIZE(ftm_quaddec_count_functions),
+ .synapses = ftm_quaddec_count_synapses,
+ .num_synapses = ARRAY_SIZE(ftm_quaddec_count_synapses),
+ .ext = ftm_quaddec_count_ext,
+ .num_ext = ARRAY_SIZE(ftm_quaddec_count_ext)
+};
+
+static int ftm_quaddec_probe(struct platform_device *pdev)
+{
+ struct ftm_quaddec *ftm;
+
+ struct device_node *node = pdev->dev.of_node;
+ struct resource *io;
+ int ret;
+
+ ftm = devm_kzalloc(&pdev->dev, sizeof(*ftm), GFP_KERNEL);
+ if (!ftm)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ftm);
+
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!io) {
+ dev_err(&pdev->dev, "Failed to get memory region\n");
+ return -ENODEV;
+ }
+
+ ftm->pdev = pdev;
+ ftm->big_endian = of_property_read_bool(node, "big-endian");
+ ftm->ftm_base = devm_ioremap(&pdev->dev, io->start, resource_size(io));
+
+ if (!ftm->ftm_base) {
+ dev_err(&pdev->dev, "Failed to map memory region\n");
+ return -EINVAL;
+ }
+ ftm->counter.name = dev_name(&pdev->dev);
+ ftm->counter.parent = &pdev->dev;
+ ftm->counter.ops = &ftm_quaddec_cnt_ops;
+ ftm->counter.counts = &ftm_quaddec_counts;
+ ftm->counter.num_counts = 1;
+ ftm->counter.signals = ftm_quaddec_signals;
+ ftm->counter.num_signals = ARRAY_SIZE(ftm_quaddec_signals);
+ ftm->counter.priv = ftm;
+
+ mutex_init(&ftm->ftm_quaddec_mutex);
+
+ ftm_quaddec_init(ftm);
+
+ ret = counter_register(&ftm->counter);
+ if (ret)
+ ftm_quaddec_disable(ftm);
+
+ return ret;
+}
+
+static int ftm_quaddec_remove(struct platform_device *pdev)
+{
+ struct ftm_quaddec *ftm = platform_get_drvdata(pdev);
+
+ counter_unregister(&ftm->counter);
+
+ ftm_quaddec_disable(ftm);
+
+ return 0;
+}
+
+static const struct of_device_id ftm_quaddec_match[] = {
+ { .compatible = "fsl,ftm-quaddec" },
+ {},
+};
+
+static struct platform_driver ftm_quaddec_driver = {
+ .driver = {
+ .name = "ftm-quaddec",
+ .of_match_table = ftm_quaddec_match,
+ },
+ .probe = ftm_quaddec_probe,
+ .remove = ftm_quaddec_remove,
+};
+
+module_platform_driver(ftm_quaddec_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com");
+MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com");
--
2.21.0
^ permalink raw reply related
* [PATCH v10 17/18] counter: ftm-quaddec: Documentation: Add specific counter sysfs documentation
From: William Breathitt Gray @ 2019-04-02 6:30 UTC (permalink / raw)
To: gregkh
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, William Breathitt Gray,
robh+dt, tglx, fabrice.gasnier, esben, shawnguo, linux-kernel,
leoyang.li, knaack.h, akpm, linuxppc-dev, jic23
In-Reply-To: <cover.1554184734.git.vilhelm.gray@gmail.com>
From: Patrick Havelange <patrick.havelange@essensium.com>
This adds documentation for the specific prescaler entry.
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
.../ABI/testing/sysfs-bus-counter-ftm-quaddec | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
diff --git a/Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec b/Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
new file mode 100644
index 000000000000..7d2e7b363467
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
@@ -0,0 +1,16 @@
+What: /sys/bus/counter/devices/counterX/countY/prescaler_available
+KernelVersion: 5.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ Discrete set of available values for the respective Count Y
+ configuration are listed in this file. Values are delimited by
+ newline characters.
+
+What: /sys/bus/counter/devices/counterX/countY/prescaler
+KernelVersion: 5.2
+Contact: linux-iio@vger.kernel.org
+Description:
+ Configure the prescaler value associated with Count Y.
+ On the FlexTimer, the counter clock source passes through a
+ prescaler (i.e. a counter). This acts like a clock
+ divider.
--
2.21.0
^ permalink raw reply related
* [PATCH v10 18/18] LS1021A: dtsi: add ftm quad decoder entries
From: William Breathitt Gray @ 2019-04-02 6:30 UTC (permalink / raw)
To: gregkh
Cc: mark.rutland, benjamin.gaignard, linux-pwm, linux-iio,
patrick.havelange, thierry.reding, pmeerw, lars, daniel.lezcano,
linux-arm-kernel, devicetree, david, William Breathitt Gray,
robh+dt, tglx, fabrice.gasnier, esben, shawnguo, linux-kernel,
leoyang.li, knaack.h, akpm, linuxppc-dev, jic23
In-Reply-To: <cover.1554184734.git.vilhelm.gray@gmail.com>
From: Patrick Havelange <patrick.havelange@essensium.com>
Add the 4 Quadrature counters for this board.
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
arch/arm/boot/dts/ls1021a.dtsi | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index ed0941292172..0168fb62590a 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -433,6 +433,34 @@
status = "disabled";
};
+ counter0: counter@29d0000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
+
+ counter1: counter@29e0000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x29e0000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
+
+ counter2: counter@29f0000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x29f0000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
+
+ counter3: counter@2a00000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x2a00000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
+
gpio0: gpio@2300000 {
compatible = "fsl,ls1021a-gpio", "fsl,qoriq-gpio";
reg = <0x0 0x2300000 0x0 0x10000>;
--
2.21.0
^ permalink raw reply related
* Re: [PATCH stable v4.14 13/32] powerpc/fsl: Add barrier_nospec implementation for NXP PowerPC Book3E
From: Joakim Tjernlund @ 2019-04-02 6:56 UTC (permalink / raw)
To: mpe@ellerman.id.au, stable@vger.kernel.org,
gregkh@linuxfoundation.org
Cc: diana.craciun@nxp.com, linuxppc-dev@ozlabs.org, msuchanek@suse.de
In-Reply-To: <87imvxorn7.fsf@concordia.ellerman.id.au>
On Tue, 2019-04-02 at 17:19 +1100, Michael Ellerman wrote:
>
> Joakim Tjernlund <Joakim.Tjernlund@infinera.com> writes:
> > On Fri, 2019-03-29 at 22:26 +1100, Michael Ellerman wrote:
> > > From: Diana Craciun <diana.craciun@nxp.com>
> > >
> > > commit ebcd1bfc33c7a90df941df68a6e5d4018c022fba upstream.
> > >
> > > Implement the barrier_nospec as a isync;sync instruction sequence.
> > > The implementation uses the infrastructure built for BOOK3S 64.
> > >
> > > Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
> > > [mpe: Split out of larger patch]
> > > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> >
> > What is the performanc impact of these spectre fixes?
>
> I've not seen any numbers from anyone.
Thanks for getting back to me.
>
> It will depend on the workload, it's copy to/from user that is most
> likely to show an impact.
>
> We have a context switch benchmark in
> tools/testing/selftests/powerpc/benchmarks/context_switch.c.
>
> Running that with "--no-vector --no-altivec --no-fp --test=pipe" shows
> about a 2.3% slow down vs booting with "nospectre_v1".
>
> > Can I compile it away?
>
> You can't actually, but you can disable it at runtime with
> "nospectre_v1" on the kernel command line.
>
> We could make it a user selectable compile time option if you really
> want it to be.
I think yes. Considering that these patches are fairly untested and the impact
in the wild unknown. Requiring systems to change their boot config over night is
too fast.
Jocke
^ permalink raw reply
* Re: [PATCH 2/5] powerpc: Fix vDSO clock_getres()
From: Vincenzo Frascino @ 2019-04-02 9:00 UTC (permalink / raw)
To: Christophe Leroy, linux-arch, linux-arm-kernel, linuxppc-dev,
linux-s390
Cc: Arnd Bergmann, Heiko Carstens, Catalin Marinas, Will Deacon,
Paul Mackerras, Greentime Hu, Martin Schwidefsky, Thomas Gleixner,
Vincent Chen, Shuah Khan
In-Reply-To: <f54a24fe-f893-10c9-9177-4985bad2e745@c-s.fr>
Hi Christophe,
thank you for your review.
On 02/04/2019 06:54, Christophe Leroy wrote:
>
>
> On 04/01/2019 11:51 AM, Vincenzo Frascino wrote:
>> clock_getres in the vDSO library has to preserve the same behaviour
>> of posix_get_hrtimer_res().
>>
>> In particular, posix_get_hrtimer_res() does:
>> sec = 0;
>> ns = hrtimer_resolution;
>> and hrtimer_resolution depends on the enablement of the high
>> resolution timers that can happen either at compile or at run time.
>>
>> Fix the powerpc vdso implementation of clock_getres keeping a copy of
>> hrtimer_resolution in vdso data and using that directly.
>>
>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: Michael Ellerman <mpe@ellerman.id.au>
>> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
>> ---
>> arch/powerpc/include/asm/vdso_datapage.h | 2 ++
>
> Conflicts with commit b5b4453e7912 ("powerpc/vdso64: Fix CLOCK_MONOTONIC
> inconsistencies across Y2038")
>
Thanks for pointing this out, I will rebase my code on top of the latest version
before reissuing v2.
...
--
Regards,
Vincenzo
^ permalink raw reply
* Re: [PATCH 2/5] powerpc: Fix vDSO clock_getres()
From: Vincenzo Frascino @ 2019-04-02 9:01 UTC (permalink / raw)
To: Christophe Leroy, linux-arch, linux-arm-kernel, linuxppc-dev,
linux-s390
Cc: Arnd Bergmann, Heiko Carstens, Catalin Marinas, Will Deacon,
Paul Mackerras, Greentime Hu, Martin Schwidefsky, Thomas Gleixner,
Vincent Chen, Shuah Khan
In-Reply-To: <5a76f55d-eb0d-fb49-8e59-f0e89e561f7b@c-s.fr>
On 02/04/2019 07:14, Christophe Leroy wrote:
>
>
> On 04/01/2019 11:51 AM, Vincenzo Frascino wrote:
>> clock_getres in the vDSO library has to preserve the same behaviour
>> of posix_get_hrtimer_res().
>>
>> In particular, posix_get_hrtimer_res() does:
>> sec = 0;
>> ns = hrtimer_resolution;
>> and hrtimer_resolution depends on the enablement of the high
>> resolution timers that can happen either at compile or at run time.
>>
>> Fix the powerpc vdso implementation of clock_getres keeping a copy of
>> hrtimer_resolution in vdso data and using that directly.
>>
>> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: Michael Ellerman <mpe@ellerman.id.au>
>> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
>> ---
>> arch/powerpc/include/asm/vdso_datapage.h | 2 ++
>> arch/powerpc/kernel/asm-offsets.c | 2 +-
>> arch/powerpc/kernel/time.c | 1 +
>> arch/powerpc/kernel/vdso32/gettimeofday.S | 22 +++++++++++++++-------
>> arch/powerpc/kernel/vdso64/gettimeofday.S | 22 +++++++++++++++-------
>> 5 files changed, 34 insertions(+), 15 deletions(-)
>>
>
> [...]
>
>> diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
>> index 1e0bc5955a40..b21630079496 100644
>> --- a/arch/powerpc/kernel/vdso32/gettimeofday.S
>> +++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
>> @@ -160,14 +160,21 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
>> cror cr0*4+eq,cr0*4+eq,cr1*4+eq
>> bne cr0,99f
>>
>> - li r3,0
>> - cmpli cr0,r4,0
>> + mflr r12
>> + .cfi_register lr,r12
>> + mr r11,r4
>> + bl __get_datapage@local
>> + lwz r5,CLOCK_REALTIME_RES(r3)
>> + li r4,0
>> + cmplwi r11,0 /* check if res is NULL */
>> + beq 1f
>> +
>> + stw r4,TSPC32_TV_SEC(r11)
>> + stw r5,TSPC32_TV_NSEC(r11)
>> +
>> +1: mtlr r12
>> crclr cr0*4+so
>> - beqlr
>> - lis r5,CLOCK_REALTIME_RES@h
>> - ori r5,r5,CLOCK_REALTIME_RES@l
>> - stw r3,TSPC32_TV_SEC(r4)
>> - stw r5,TSPC32_TV_NSEC(r4)
>> + li r3,0
>> blr
>
> The above can be done simpler, see below
>
> @@ -160,12 +160,15 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
> cror cr0*4+eq,cr0*4+eq,cr1*4+eq
> bne cr0,99f
>
> + mflr r12
> + .cfi_register lr,r12
> + bl __get_datapage@local
> + lwz r5,CLOCK_REALTIME_RES(r3)
> + mtlr r12
> li r3,0
> cmpli cr0,r4,0
> crclr cr0*4+so
> beqlr
> - lis r5,CLOCK_REALTIME_RES@h
> - ori r5,r5,CLOCK_REALTIME_RES@l
> stw r3,TSPC32_TV_SEC(r4)
> stw r5,TSPC32_TV_NSEC(r4)
> blr
>
Thank you for this, I will update my code accordingly before posting v2.
> Christophe
>
>>
>> /*
>> @@ -175,6 +182,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
>> */
>> 99:
>> li r0,__NR_clock_getres
>> + .cfi_restore lr
>> sc
>> blr
>> .cfi_endproc
>> diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
>> index a4ed9edfd5f0..a7e49bddd475 100644
>> --- a/arch/powerpc/kernel/vdso64/gettimeofday.S
>> +++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
>> @@ -190,14 +190,21 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
>> cror cr0*4+eq,cr0*4+eq,cr1*4+eq
>> bne cr0,99f
>>
>> - li r3,0
>> - cmpldi cr0,r4,0
>> + mflr r12
>> + .cfi_register lr,r12
>> + mr r11, r4
>> + bl V_LOCAL_FUNC(__get_datapage)
>> + lwz r5,CLOCK_REALTIME_RES(r3)
>> + li r4,0
>> + cmpldi r11,0 /* check if res is NULL */
>> + beq 1f
>> +
>> + std r4,TSPC64_TV_SEC(r11)
>> + std r5,TSPC64_TV_NSEC(r11)
>> +
>> +1: mtlr r12
>> crclr cr0*4+so
>> - beqlr
>> - lis r5,CLOCK_REALTIME_RES@h
>> - ori r5,r5,CLOCK_REALTIME_RES@l
>> - std r3,TSPC64_TV_SEC(r4)
>> - std r5,TSPC64_TV_NSEC(r4)
>> + li r3,0
>> blr
>
> The same type of simplification applies here too.
>
> Christophe
>
>
>>
>> /*
>> @@ -205,6 +212,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
>> */
>> 99:
>> li r0,__NR_clock_getres
>> + .cfi_restore lr
>> sc
>> blr
>> .cfi_endproc
>>
--
Regards,
Vincenzo
^ permalink raw reply
* [PATCH 0/9] Improve boot command line handling
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
The purpose of this series is to improve and enhance the
handling of kernel boot arguments.
It is first focussed on powerpc but also extends the capability
for other arches.
This is based on suggestion from Daniel Walker <danielwa@cisco.com>
Christophe Leroy (9):
powerpc: enable appending of CONFIG_CMDLINE to bootloader's cmdline.
Add generic function to build command line.
drivers: of: use cmdline building function
powerpc/prom_init: get rid of PROM_SCRATCH_SIZE
powerpc: convert to generic builtin command line
Add capability to prepend the command line
powerpc: add capability to prepend default command line
Gives arches opportunity to use generically defined boot cmdline
manipulation
powerpc: use generic CMDLINE manipulations
arch/powerpc/Kconfig | 23 ++------------
arch/powerpc/kernel/prom_init.c | 38 ++++++++++-------------
arch/powerpc/kernel/prom_init_check.sh | 2 +-
drivers/of/fdt.c | 23 +++-----------
include/linux/cmdline.h | 37 ++++++++++++++++++++++
init/Kconfig | 56 ++++++++++++++++++++++++++++++++++
6 files changed, 117 insertions(+), 62 deletions(-)
create mode 100644 include/linux/cmdline.h
--
2.13.3
^ permalink raw reply
* [PATCH 2/9] Add generic function to build command line.
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This code provides architectures with a way to build command line
based on what is built in the kernel and what is handed over by the
bootloader, based on selected compile-time options.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
include/linux/cmdline.h | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 include/linux/cmdline.h
diff --git a/include/linux/cmdline.h b/include/linux/cmdline.h
new file mode 100644
index 000000000000..8610ddf813ff
--- /dev/null
+++ b/include/linux/cmdline.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_CMDLINE_H
+#define _LINUX_CMDLINE_H
+
+/*
+ * This function will append a builtin command line to the command
+ * line provided by the bootloader. Kconfig options can be used to alter
+ * the behavior of this builtin command line.
+ * @dest: The destination of the final appended/prepended string.
+ * @src: The starting string or NULL if there isn't one. Must not equal dest.
+ * @length: the length of dest buffer.
+ */
+static __always_inline void cmdline_build(char *dest, char *src, size_t length)
+{
+ if (length <= 0)
+ return;
+
+ dest[0] = 0;
+
+#ifdef CONFIG_CMDLINE
+ if (IS_ENABLED(CONFIG_CMDLINE_FORCE) || !src || !src[0]) {
+ strlcat(dest, CONFIG_CMDLINE, length);
+ return;
+ }
+#endif
+ if (dest != src)
+ strlcat(dest, src, length);
+#ifdef CONFIG_CMDLINE
+ if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) && sizeof(CONFIG_CMDLINE) > 1)
+ strlcat(dest, " " CONFIG_CMDLINE, length);
+#endif
+}
+
+#endif /* _LINUX_CMDLINE_H */
--
2.13.3
^ permalink raw reply related
* [PATCH 1/9] powerpc: enable appending of CONFIG_CMDLINE to bootloader's cmdline.
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
Today, powerpc defined CONFIG_CMDLINE for when bootloader doesn't
provide a command line or for overriding it.
On same way as ARM, this patch adds the option of appending the
CONFIG_CMDLINE to bootloader's provided command line.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 21 ++++++++++++++++++++-
arch/powerpc/kernel/prom_init.c | 5 ++---
arch/powerpc/kernel/prom_init_check.sh | 2 +-
3 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2d0be82c3061..2972348e52be 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -841,14 +841,33 @@ config CMDLINE
some command-line options at build time by entering them here. In
most cases you will need to specify the root device here.
+choice
+ prompt "Kernel command line type" if CMDLINE != ""
+ default CMDLINE_FROM_BOOTLOADER
+ help
+ Selects the way you want to use the default kernel arguments.
+
+config CMDLINE_FROM_BOOTLOADER
+ bool "Use bootloader kernel arguments if available"
+ help
+ Uses the command-line options passed by the boot loader. If
+ the boot loader doesn't provide any, the default kernel command
+ string provided in CMDLINE will be used.
+
+config CMDLINE_EXTEND
+ bool "Extend bootloader kernel arguments"
+ help
+ The default kernel command string will be appended to the
+ command-line arguments provided during boot.
+
config CMDLINE_FORCE
bool "Always use the default kernel command string"
- depends on CMDLINE_BOOL
help
Always use the default kernel command string, even if the boot
loader passes other arguments to the kernel.
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
+endchoice
config EXTRA_TARGETS
string "Additional default image types"
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index f33ff4163a51..a6cd52240c58 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -638,9 +638,8 @@ static void __init early_cmdline_parse(void)
if ((long)prom.chosen > 0)
l = prom_getprop(prom.chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
#ifdef CONFIG_CMDLINE
- if (l <= 0 || p[0] == '\0') /* dbl check */
- strlcpy(prom_cmd_line,
- CONFIG_CMDLINE, sizeof(prom_cmd_line));
+ if (l <= 0 || p[0] == '\0' || IS_ENABLED(CONFIG_CMDLINE_EXTEND)) /* dbl check */
+ strlcat(prom_cmd_line, CONFIG_CMDLINE, sizeof(prom_cmd_line));
#endif /* CONFIG_CMDLINE */
prom_printf("command line: %s\n", prom_cmd_line);
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh
index 667df97d2595..cbcf18846392 100644
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -19,7 +19,7 @@
WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
_end enter_prom memcpy memset reloc_offset __secondary_hold
__secondary_hold_acknowledge __secondary_hold_spinloop __start
-strcmp strcpy strlcpy strlen strncmp strstr kstrtobool logo_linux_clut224
+strcmp strcpy strlcat strlen strncmp strstr kstrtobool logo_linux_clut224
reloc_got2 kernstart_addr memstart_addr linux_banner _stext
__prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."
--
2.13.3
^ permalink raw reply related
* [PATCH 3/9] drivers: of: use cmdline building function
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This patch uses the new cmdline building function to
concatenate the of provided cmdline with built-in parts
based on compile-time options.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
drivers/of/fdt.c | 23 ++++-------------------
include/linux/cmdline.h | 2 +-
2 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 4734223ab702..c6d941785b37 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -24,6 +24,7 @@
#include <linux/debugfs.h>
#include <linux/serial_core.h>
#include <linux/sysfs.h>
+#include <linux/cmdline.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include <asm/page.h>
@@ -1090,26 +1091,10 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
/* Retrieve command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
+ if (l <= 0)
+ p = NULL;
- /*
- * CONFIG_CMDLINE is meant to be a default in case nothing else
- * managed to set the command line, unless CONFIG_CMDLINE_FORCE
- * is set in which case we override whatever was found earlier.
- */
-#ifdef CONFIG_CMDLINE
-#if defined(CONFIG_CMDLINE_EXTEND)
- strlcat(data, " ", COMMAND_LINE_SIZE);
- strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#elif defined(CONFIG_CMDLINE_FORCE)
- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#else
- /* No arguments from boot loader, use kernel's cmdl*/
- if (!((char *)data)[0])
- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif
-#endif /* CONFIG_CMDLINE */
+ cmdline_build(data, p, COMMAND_LINE_SIZE);
pr_debug("Command line is: %s\n", (char*)data);
diff --git a/include/linux/cmdline.h b/include/linux/cmdline.h
index 8610ddf813ff..afcc00d7628d 100644
--- a/include/linux/cmdline.h
+++ b/include/linux/cmdline.h
@@ -10,7 +10,7 @@
* @src: The starting string or NULL if there isn't one. Must not equal dest.
* @length: the length of dest buffer.
*/
-static __always_inline void cmdline_build(char *dest, char *src, size_t length)
+static __always_inline void cmdline_build(char *dest, const char *src, size_t length)
{
if (length <= 0)
return;
--
2.13.3
^ permalink raw reply related
* [PATCH 4/9] powerpc/prom_init: get rid of PROM_SCRATCH_SIZE
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
PROM_SCRATCH_SIZE is same as sizeof(prom_scratch)
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/prom_init.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index a6cd52240c58..d4889ba04ddd 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -154,10 +154,8 @@ static struct prom_t __prombss prom;
static unsigned long __prombss prom_entry;
-#define PROM_SCRATCH_SIZE 256
-
static char __prombss of_stdout_device[256];
-static char __prombss prom_scratch[PROM_SCRATCH_SIZE];
+static char __prombss prom_scratch[256];
static unsigned long __prombss dt_header_start;
static unsigned long __prombss dt_struct_start, dt_struct_end;
@@ -1486,8 +1484,8 @@ static void __init prom_init_mem(void)
endp = p + (plen / sizeof(cell_t));
#ifdef DEBUG_PROM
- memset(path, 0, PROM_SCRATCH_SIZE);
- call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+ memset(path, 0, sizeof(prom_scratch));
+ call_prom("package-to-path", 3, 1, node, path, sizeof(prom_scratch) - 1);
prom_debug(" node %s :\n", path);
#endif /* DEBUG_PROM */
@@ -1795,10 +1793,10 @@ static void __init prom_initialize_tce_table(void)
local_alloc_bottom = base;
/* It seems OF doesn't null-terminate the path :-( */
- memset(path, 0, PROM_SCRATCH_SIZE);
+ memset(path, 0, sizeof(prom_scratch));
/* Call OF to setup the TCE hardware */
if (call_prom("package-to-path", 3, 1, node,
- path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) {
+ path, sizeof(prom_scratch) - 1) == PROM_ERROR) {
prom_printf("package-to-path failed\n");
}
@@ -2159,14 +2157,14 @@ static void __init prom_check_displays(void)
/* It seems OF doesn't null-terminate the path :-( */
path = prom_scratch;
- memset(path, 0, PROM_SCRATCH_SIZE);
+ memset(path, 0, sizeof(prom_scratch));
/*
* leave some room at the end of the path for appending extra
* arguments
*/
if (call_prom("package-to-path", 3, 1, node, path,
- PROM_SCRATCH_SIZE-10) == PROM_ERROR)
+ sizeof(prom_scratch) - 10) == PROM_ERROR)
continue;
prom_printf("found display : %s, opening... ", path);
@@ -2362,8 +2360,8 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
/* get it again for debugging */
path = prom_scratch;
- memset(path, 0, PROM_SCRATCH_SIZE);
- call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
+ memset(path, 0, sizeof(prom_scratch));
+ call_prom("package-to-path", 3, 1, node, path, sizeof(prom_scratch) - 1);
/* get and store all properties */
prev_name = "";
--
2.13.3
^ permalink raw reply related
* [PATCH 6/9] Add capability to prepend the command line
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This patchs adds an option of prepend a text to the command
line instead of appending it.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
include/linux/cmdline.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/include/linux/cmdline.h b/include/linux/cmdline.h
index afcc00d7628d..5caf3724c1ab 100644
--- a/include/linux/cmdline.h
+++ b/include/linux/cmdline.h
@@ -3,7 +3,7 @@
#define _LINUX_CMDLINE_H
/*
- * This function will append a builtin command line to the command
+ * This function will append or prepend a builtin command line to the command
* line provided by the bootloader. Kconfig options can be used to alter
* the behavior of this builtin command line.
* @dest: The destination of the final appended/prepended string.
@@ -22,6 +22,9 @@ static __always_inline void cmdline_build(char *dest, const char *src, size_t le
strlcat(dest, CONFIG_CMDLINE, length);
return;
}
+
+ if (IS_ENABLED(CONFIG_CMDLINE_PREPEND) && sizeof(CONFIG_CMDLINE) > 1)
+ strlcat(dest, CONFIG_CMDLINE " ", length);
#endif
if (dest != src)
strlcat(dest, src, length);
--
2.13.3
^ permalink raw reply related
* [PATCH 7/9] powerpc: add capability to prepend default command line
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This patch activates the capability to prepend default
arguments to the command line.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2972348e52be..22d6a48bd2ca 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -860,6 +860,12 @@ config CMDLINE_EXTEND
The default kernel command string will be appended to the
command-line arguments provided during boot.
+config CMDLINE_PREPEND
+ bool "Prepend bootloader kernel arguments"
+ help
+ The default kernel command string will be prepend to the
+ command-line arguments provided during boot.
+
config CMDLINE_FORCE
bool "Always use the default kernel command string"
help
--
2.13.3
^ permalink raw reply related
* [PATCH 5/9] powerpc: convert to generic builtin command line
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This updates the powerpc code to use the new cmdline building function.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/prom_init.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index d4889ba04ddd..08f3db25b2f1 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -30,6 +30,7 @@
#include <linux/delay.h>
#include <linux/initrd.h>
#include <linux/bitops.h>
+#include <linux/cmdline.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/page.h>
@@ -155,7 +156,7 @@ static struct prom_t __prombss prom;
static unsigned long __prombss prom_entry;
static char __prombss of_stdout_device[256];
-static char __prombss prom_scratch[256];
+static char __prombss prom_scratch[COMMAND_LINE_SIZE];
static unsigned long __prombss dt_header_start;
static unsigned long __prombss dt_struct_start, dt_struct_end;
@@ -627,18 +628,14 @@ static unsigned long prom_memparse(const char *ptr, const char **retptr)
static void __init early_cmdline_parse(void)
{
const char *opt;
+ int l = 0;
- char *p;
- int l __maybe_unused = 0;
-
- prom_cmd_line[0] = 0;
- p = prom_cmd_line;
if ((long)prom.chosen > 0)
- l = prom_getprop(prom.chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
-#ifdef CONFIG_CMDLINE
- if (l <= 0 || p[0] == '\0' || IS_ENABLED(CONFIG_CMDLINE_EXTEND)) /* dbl check */
- strlcat(prom_cmd_line, CONFIG_CMDLINE, sizeof(prom_cmd_line));
-#endif /* CONFIG_CMDLINE */
+ l = prom_getprop(prom.chosen, "bootargs", prom_scratch,
+ COMMAND_LINE_SIZE - 1);
+
+ cmdline_build(prom_cmd_line, l > 0 ? prom_scratch : NULL, sizeof(prom_scratch));
+
prom_printf("command line: %s\n", prom_cmd_line);
#ifdef CONFIG_PPC64
--
2.13.3
^ permalink raw reply related
* [PATCH 8/9] Gives arches opportunity to use generically defined boot cmdline manipulation
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
Most arches have similar boot command line manipulation options.
This patchs adds the definition in init/Kconfig, gated by
CONFIG_HAVE_CMDLINE that the arches can select to use them.
In order to use this, a few arches will have to change their
CONFIG options:
- riscv has to replace CMDLINE_FALLBACK by CMDLINE_FROM_BOOTLOADER
- arches using CONFIG_CMDLINE_OVERRIDE or CONFIG_CMDLINE_OVERWRITE
have to replace them by CONFIG_CMDLINE_FORCE
Arches also have to define CONFIG_DEFAULT_CMDLINE
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
init/Kconfig | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/init/Kconfig b/init/Kconfig
index 4592bf7997c0..83537603412c 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -80,6 +80,62 @@ config INIT_ENV_ARG_LIMIT
Maximum of each of the number of arguments and environment
variables passed to init from the kernel command line.
+config HAVE_CMDLINE
+ bool
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+ depends on HAVE_CMDLINE
+ help
+ On some platforms, there is currently no way for the boot loader to
+ pass arguments to the kernel. For these platforms, you can supply
+ some command-line options at build time by entering them here. In
+ most cases you will need to specify the root device here.
+
+config CMDLINE
+ string "Initial kernel command string"
+ depends on CMDLINE_BOOL
+ default DEFAULT_CMDLINE
+ help
+ On some platforms, there is currently no way for the boot loader to
+ pass arguments to the kernel. For these platforms, you can supply
+ some command-line options at build time by entering them here. In
+ most cases you will need to specify the root device here.
+
+choice
+ prompt "Kernel command line type" if CMDLINE != ""
+ default CMDLINE_FROM_BOOTLOADER
+ help
+ Selects the way you want to use the default kernel arguments.
+
+config CMDLINE_FROM_BOOTLOADER
+ bool "Use bootloader kernel arguments if available"
+ help
+ Uses the command-line options passed by the boot loader. If
+ the boot loader doesn't provide any, the default kernel command
+ string provided in CMDLINE will be used.
+
+config CMDLINE_EXTEND
+ bool "Extend bootloader kernel arguments"
+ help
+ The default kernel command string will be appended to the
+ command-line arguments provided during boot.
+
+config CMDLINE_PREPEND
+ bool "Prepend bootloader kernel arguments"
+ help
+ The default kernel command string will be prepend to the
+ command-line arguments provided during boot.
+
+config CMDLINE_FORCE
+ bool "Always use the default kernel command string"
+ help
+ Always use the default kernel command string, even if the boot
+ loader passes other arguments to the kernel.
+ This is useful if you cannot or don't want to change the
+ command-line options your boot loader passes to the kernel.
+endchoice
+
config COMPILE_TEST
bool "Compile also drivers which will not load"
depends on !UML
--
2.13.3
^ permalink raw reply related
* [PATCH 9/9] powerpc: use generic CMDLINE manipulations
From: Christophe Leroy @ 2019-04-02 9:08 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
danielwa
Cc: linux-arch, linuxppc-dev, linux-kernel
In-Reply-To: <cover.1554195798.git.christophe.leroy@c-s.fr>
This patch moves powerpc to the centraly defined CMDLINE options.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 48 +++---------------------------------------------
1 file changed, 3 insertions(+), 45 deletions(-)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 22d6a48bd2ca..6a71d7c514cc 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -182,6 +182,7 @@ config PPC
select HAVE_CBPF_JIT if !PPC64
select HAVE_STACKPROTECTOR if PPC64 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r13)
select HAVE_STACKPROTECTOR if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2)
+ select HAVE_CMDLINE
select HAVE_CONTEXT_TRACKING if PPC64
select HAVE_DEBUG_KMEMLEAK
select HAVE_DEBUG_STACKOVERFLOW
@@ -828,52 +829,9 @@ config PPC_DENORMALISATION
Add support for handling denormalisation of single precision
values. Useful for bare metal only. If unsure say Y here.
-config CMDLINE_BOOL
- bool "Default bootloader kernel arguments"
-
-config CMDLINE
- string "Initial kernel command string"
- depends on CMDLINE_BOOL
+config DEFAULT_CMDLINE
+ string
default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
- help
- On some platforms, there is currently no way for the boot loader to
- pass arguments to the kernel. For these platforms, you can supply
- some command-line options at build time by entering them here. In
- most cases you will need to specify the root device here.
-
-choice
- prompt "Kernel command line type" if CMDLINE != ""
- default CMDLINE_FROM_BOOTLOADER
- help
- Selects the way you want to use the default kernel arguments.
-
-config CMDLINE_FROM_BOOTLOADER
- bool "Use bootloader kernel arguments if available"
- help
- Uses the command-line options passed by the boot loader. If
- the boot loader doesn't provide any, the default kernel command
- string provided in CMDLINE will be used.
-
-config CMDLINE_EXTEND
- bool "Extend bootloader kernel arguments"
- help
- The default kernel command string will be appended to the
- command-line arguments provided during boot.
-
-config CMDLINE_PREPEND
- bool "Prepend bootloader kernel arguments"
- help
- The default kernel command string will be prepend to the
- command-line arguments provided during boot.
-
-config CMDLINE_FORCE
- bool "Always use the default kernel command string"
- help
- Always use the default kernel command string, even if the boot
- loader passes other arguments to the kernel.
- This is useful if you cannot or don't want to change the
- command-line options your boot loader passes to the kernel.
-endchoice
config EXTRA_TARGETS
string "Additional default image types"
--
2.13.3
^ permalink raw reply related
* Re: [RFC PATCH v2 3/3] kasan: add interceptors for all string functions
From: Christophe Leroy @ 2019-04-02 9:43 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman,
Nicholas Piggin, Aneesh Kumar K.V, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Daniel Axtens
Cc: linux-mm, linuxppc-dev, linux-kernel, kasan-dev
In-Reply-To: <51a6d9d7185de310f37ccbd7e4ebfdd6c7e9791f.1553785020.git.christophe.leroy@c-s.fr>
Hi Dmitry, Andrey and others,
Do you have any comments to this series ?
I'd like to know if this approach is ok or if it is better to keep doing
as in https://patchwork.ozlabs.org/patch/1055788/
Thanks
Christophe
Le 28/03/2019 à 16:00, Christophe Leroy a écrit :
> In the same spirit as commit 393f203f5fd5 ("x86_64: kasan: add
> interceptors for memset/memmove/memcpy functions"), this patch
> adds interceptors for string manipulation functions so that we
> can compile lib/string.o without kasan support hence allow the
> string functions to also be used from places where kasan has
> to be disabled.
>
> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
> ---
> v2: Fixed a few checkpatch stuff and added missing EXPORT_SYMBOL() and missing #undefs
>
> include/linux/string.h | 79 ++++++++++
> lib/Makefile | 2 +
> lib/string.c | 8 +
> mm/kasan/string.c | 394 +++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 483 insertions(+)
>
> diff --git a/include/linux/string.h b/include/linux/string.h
> index 7927b875f80c..3d2aff2ed402 100644
> --- a/include/linux/string.h
> +++ b/include/linux/string.h
> @@ -19,54 +19,117 @@ extern void *memdup_user_nul(const void __user *, size_t);
> */
> #include <asm/string.h>
>
> +#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
> +/*
> + * For files that are not instrumented (e.g. mm/slub.c) we
> + * should use not instrumented version of mem* functions.
> + */
> +#define memset16 __memset16
> +#define memset32 __memset32
> +#define memset64 __memset64
> +#define memzero_explicit __memzero_explicit
> +#define strcpy __strcpy
> +#define strncpy __strncpy
> +#define strlcpy __strlcpy
> +#define strscpy __strscpy
> +#define strcat __strcat
> +#define strncat __strncat
> +#define strlcat __strlcat
> +#define strcmp __strcmp
> +#define strncmp __strncmp
> +#define strcasecmp __strcasecmp
> +#define strncasecmp __strncasecmp
> +#define strchr __strchr
> +#define strchrnul __strchrnul
> +#define strrchr __strrchr
> +#define strnchr __strnchr
> +#define skip_spaces __skip_spaces
> +#define strim __strim
> +#define strstr __strstr
> +#define strnstr __strnstr
> +#define strlen __strlen
> +#define strnlen __strnlen
> +#define strpbrk __strpbrk
> +#define strsep __strsep
> +#define strspn __strspn
> +#define strcspn __strcspn
> +#define memscan __memscan
> +#define memcmp __memcmp
> +#define memchr __memchr
> +#define memchr_inv __memchr_inv
> +#define strreplace __strreplace
> +
> +#ifndef __NO_FORTIFY
> +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
> +#endif
> +
> +#endif
> +
> #ifndef __HAVE_ARCH_STRCPY
> extern char * strcpy(char *,const char *);
> +char *__strcpy(char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRNCPY
> extern char * strncpy(char *,const char *, __kernel_size_t);
> +char *__strncpy(char *, const char *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_STRLCPY
> size_t strlcpy(char *, const char *, size_t);
> +size_t __strlcpy(char *, const char *, size_t);
> #endif
> #ifndef __HAVE_ARCH_STRSCPY
> ssize_t strscpy(char *, const char *, size_t);
> +ssize_t __strscpy(char *, const char *, size_t);
> #endif
> #ifndef __HAVE_ARCH_STRCAT
> extern char * strcat(char *, const char *);
> +char *__strcat(char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRNCAT
> extern char * strncat(char *, const char *, __kernel_size_t);
> +char *__strncat(char *, const char *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_STRLCAT
> extern size_t strlcat(char *, const char *, __kernel_size_t);
> +size_t __strlcat(char *, const char *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_STRCMP
> extern int strcmp(const char *,const char *);
> +int __strcmp(const char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRNCMP
> extern int strncmp(const char *,const char *,__kernel_size_t);
> +int __strncmp(const char *, const char *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_STRCASECMP
> extern int strcasecmp(const char *s1, const char *s2);
> +int __strcasecmp(const char *s1, const char *s2);
> #endif
> #ifndef __HAVE_ARCH_STRNCASECMP
> extern int strncasecmp(const char *s1, const char *s2, size_t n);
> +int __strncasecmp(const char *s1, const char *s2, size_t n);
> #endif
> #ifndef __HAVE_ARCH_STRCHR
> extern char * strchr(const char *,int);
> +char *__strchr(const char *, int);
> #endif
> #ifndef __HAVE_ARCH_STRCHRNUL
> extern char * strchrnul(const char *,int);
> +char *__strchrnul(const char *, int);
> #endif
> #ifndef __HAVE_ARCH_STRNCHR
> extern char * strnchr(const char *, size_t, int);
> +char *__strnchr(const char *, size_t, int);
> #endif
> #ifndef __HAVE_ARCH_STRRCHR
> extern char * strrchr(const char *,int);
> +char *__strrchr(const char *, int);
> #endif
> extern char * __must_check skip_spaces(const char *);
> +char * __must_check __skip_spaces(const char *);
>
> extern char *strim(char *);
> +char *__strim(char *);
>
> static inline __must_check char *strstrip(char *str)
> {
> @@ -75,27 +138,35 @@ static inline __must_check char *strstrip(char *str)
>
> #ifndef __HAVE_ARCH_STRSTR
> extern char * strstr(const char *, const char *);
> +char *__strstr(const char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRNSTR
> extern char * strnstr(const char *, const char *, size_t);
> +char *__strnstr(const char *, const char *, size_t);
> #endif
> #ifndef __HAVE_ARCH_STRLEN
> extern __kernel_size_t strlen(const char *);
> +__kernel_size_t __strlen(const char *);
> #endif
> #ifndef __HAVE_ARCH_STRNLEN
> extern __kernel_size_t strnlen(const char *,__kernel_size_t);
> +__kernel_size_t __strnlen(const char *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_STRPBRK
> extern char * strpbrk(const char *,const char *);
> +char *__strpbrk(const char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRSEP
> extern char * strsep(char **,const char *);
> +char *__strsep(char **, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRSPN
> extern __kernel_size_t strspn(const char *,const char *);
> +__kernel_size_t __strspn(const char *, const char *);
> #endif
> #ifndef __HAVE_ARCH_STRCSPN
> extern __kernel_size_t strcspn(const char *,const char *);
> +__kernel_size_t __strcspn(const char *, const char *);
> #endif
>
> #ifndef __HAVE_ARCH_MEMSET
> @@ -104,14 +175,17 @@ extern void * memset(void *,int,__kernel_size_t);
>
> #ifndef __HAVE_ARCH_MEMSET16
> extern void *memset16(uint16_t *, uint16_t, __kernel_size_t);
> +void *__memset16(uint16_t *, uint16_t, __kernel_size_t);
> #endif
>
> #ifndef __HAVE_ARCH_MEMSET32
> extern void *memset32(uint32_t *, uint32_t, __kernel_size_t);
> +void *__memset32(uint32_t *, uint32_t, __kernel_size_t);
> #endif
>
> #ifndef __HAVE_ARCH_MEMSET64
> extern void *memset64(uint64_t *, uint64_t, __kernel_size_t);
> +void *__memset64(uint64_t *, uint64_t, __kernel_size_t);
> #endif
>
> static inline void *memset_l(unsigned long *p, unsigned long v,
> @@ -146,12 +220,15 @@ extern void * memmove(void *,const void *,__kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_MEMSCAN
> extern void * memscan(void *,int,__kernel_size_t);
> +void *__memscan(void *, int, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_MEMCMP
> extern int memcmp(const void *,const void *,__kernel_size_t);
> +int __memcmp(const void *, const void *, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_MEMCHR
> extern void * memchr(const void *,int,__kernel_size_t);
> +void *__memchr(const void *, int, __kernel_size_t);
> #endif
> #ifndef __HAVE_ARCH_MEMCPY_MCSAFE
> static inline __must_check unsigned long memcpy_mcsafe(void *dst,
> @@ -168,7 +245,9 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
> }
> #endif
> void *memchr_inv(const void *s, int c, size_t n);
> +void *__memchr_inv(const void *s, int c, size_t n);
> char *strreplace(char *s, char old, char new);
> +char *__strreplace(char *s, char old, char new);
>
> extern void kfree_const(const void *x);
>
> diff --git a/lib/Makefile b/lib/Makefile
> index 30b9b0bfbba9..19d0237f9b9c 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -18,6 +18,8 @@ KCOV_INSTRUMENT_list_debug.o := n
> KCOV_INSTRUMENT_debugobjects.o := n
> KCOV_INSTRUMENT_dynamic_debug.o := n
>
> +KASAN_SANITIZE_string.o := n
> +
> lib-y := ctype.o string.o string_sysfs.o vsprintf.o cmdline.o \
> rbtree.o radix-tree.o timerqueue.o xarray.o \
> idr.o int_sqrt.o extable.o \
> diff --git a/lib/string.c b/lib/string.c
> index f3886c5175ac..31a253201bba 100644
> --- a/lib/string.c
> +++ b/lib/string.c
> @@ -85,7 +85,9 @@ EXPORT_SYMBOL(strcasecmp);
> * @dest: Where to copy the string to
> * @src: Where to copy the string from
> */
> +#ifndef CONFIG_KASAN
> #undef strcpy
> +#endif
> char *strcpy(char *dest, const char *src)
> {
> char *tmp = dest;
> @@ -243,7 +245,9 @@ EXPORT_SYMBOL(strscpy);
> * @dest: The string to be appended to
> * @src: The string to append to it
> */
> +#ifndef CONFIG_KASAN
> #undef strcat
> +#endif
> char *strcat(char *dest, const char *src)
> {
> char *tmp = dest;
> @@ -319,7 +323,9 @@ EXPORT_SYMBOL(strlcat);
> * @cs: One string
> * @ct: Another string
> */
> +#ifndef CONFIG_KASAN
> #undef strcmp
> +#endif
> int strcmp(const char *cs, const char *ct)
> {
> unsigned char c1, c2;
> @@ -773,7 +779,9 @@ EXPORT_SYMBOL(memmove);
> * @ct: Another area of memory
> * @count: The size of the area.
> */
> +#ifndef CONFIG_KASAN
> #undef memcmp
> +#endif
> __visible int memcmp(const void *cs, const void *ct, size_t count)
> {
> const unsigned char *su1, *su2;
> diff --git a/mm/kasan/string.c b/mm/kasan/string.c
> index 083b967255a2..0db31bbbf643 100644
> --- a/mm/kasan/string.c
> +++ b/mm/kasan/string.c
> @@ -35,6 +35,42 @@ void *memset(void *addr, int c, size_t len)
> return __memset(addr, c, len);
> }
>
> +#undef memset16
> +void *memset16(uint16_t *s, uint16_t v, size_t count)
> +{
> + check_memory_region((unsigned long)s, count << 1, true, _RET_IP_);
> +
> + return __memset16(s, v, count);
> +}
> +EXPORT_SYMBOL(memset16);
> +
> +#undef memset32
> +void *memset32(uint32_t *s, uint32_t v, size_t count)
> +{
> + check_memory_region((unsigned long)s, count << 2, true, _RET_IP_);
> +
> + return __memset32(s, v, count);
> +}
> +EXPORT_SYMBOL(memset32);
> +
> +#undef memset64
> +void *memset64(uint64_t *s, uint64_t v, size_t count)
> +{
> + check_memory_region((unsigned long)s, count << 3, true, _RET_IP_);
> +
> + return __memset64(s, v, count);
> +}
> +EXPORT_SYMBOL(memset64);
> +
> +#undef memzero_explicit
> +void memzero_explicit(void *s, size_t count)
> +{
> + check_memory_region((unsigned long)s, count, true, _RET_IP_);
> +
> + return __memzero_explicit(s, count);
> +}
> +EXPORT_SYMBOL(memzero_explicit);
> +
> #undef memmove
> void *memmove(void *dest, const void *src, size_t len)
> {
> @@ -52,3 +88,361 @@ void *memcpy(void *dest, const void *src, size_t len)
>
> return __memcpy(dest, src, len);
> }
> +
> +#undef strcpy
> +char *strcpy(char *dest, const char *src)
> +{
> + size_t len = __strlen(src) + 1;
> +
> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
> +
> + return __strcpy(dest, src);
> +}
> +EXPORT_SYMBOL(strcpy);
> +
> +#undef strncpy
> +char *strncpy(char *dest, const char *src, size_t count)
> +{
> + size_t len = min(__strlen(src) + 1, count);
> +
> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, count, true, _RET_IP_);
> +
> + return __strncpy(dest, src, count);
> +}
> +EXPORT_SYMBOL(strncpy);
> +
> +#undef strlcpy
> +size_t strlcpy(char *dest, const char *src, size_t size)
> +{
> + size_t len = __strlen(src) + 1;
> +
> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, min(len, size), true, _RET_IP_);
> +
> + return __strlcpy(dest, src, size);
> +}
> +EXPORT_SYMBOL(strlcpy);
> +
> +#undef strscpy
> +ssize_t strscpy(char *dest, const char *src, size_t count)
> +{
> + int len = min(__strlen(src) + 1, count);
> +
> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
> +
> + return __strscpy(dest, src, count);
> +}
> +EXPORT_SYMBOL(strscpy);
> +
> +#undef strcat
> +char *strcat(char *dest, const char *src)
> +{
> + size_t slen = __strlen(src) + 1;
> + size_t dlen = __strlen(dest);
> +
> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> +
> + return __strcat(dest, src);
> +}
> +EXPORT_SYMBOL(strcat);
> +
> +#undef strncat
> +char *strncat(char *dest, const char *src, size_t count)
> +{
> + size_t slen = min(__strlen(src) + 1, count);
> + size_t dlen = __strlen(dest);
> +
> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> +
> + return __strncat(dest, src, count);
> +}
> +EXPORT_SYMBOL(strncat);
> +
> +#undef strlcat
> +size_t strlcat(char *dest, const char *src, size_t count)
> +{
> + size_t slen = min(__strlen(src) + 1, count);
> + size_t dlen = __strlen(dest);
> +
> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> +
> + return __strlcat(dest, src, count);
> +}
> +EXPORT_SYMBOL(strlcat);
> +
> +#undef strcmp
> +int strcmp(const char *cs, const char *ct)
> +{
> + size_t len = min(__strlen(cs) + 1, __strlen(ct) + 1);
> +
> + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
> + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
> +
> + return __strcmp(cs, ct);
> +}
> +EXPORT_SYMBOL(strcmp);
> +
> +#undef strncmp
> +int strncmp(const char *cs, const char *ct, size_t count)
> +{
> + size_t len = min3(__strlen(cs) + 1, __strlen(ct) + 1, count);
> +
> + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
> + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
> +
> + return __strncmp(cs, ct, count);
> +}
> +EXPORT_SYMBOL(strncmp);
> +
> +#undef strcasecmp
> +int strcasecmp(const char *s1, const char *s2)
> +{
> + size_t len = min(__strlen(s1) + 1, __strlen(s2) + 1);
> +
> + check_memory_region((unsigned long)s1, len, false, _RET_IP_);
> + check_memory_region((unsigned long)s2, len, false, _RET_IP_);
> +
> + return __strcasecmp(s1, s2);
> +}
> +EXPORT_SYMBOL(strcasecmp);
> +
> +#undef strncasecmp
> +int strncasecmp(const char *s1, const char *s2, size_t len)
> +{
> + size_t sz = min3(__strlen(s1) + 1, __strlen(s2) + 1, len);
> +
> + check_memory_region((unsigned long)s1, sz, false, _RET_IP_);
> + check_memory_region((unsigned long)s2, sz, false, _RET_IP_);
> +
> + return __strncasecmp(s1, s2, len);
> +}
> +EXPORT_SYMBOL(strncasecmp);
> +
> +#undef strchr
> +char *strchr(const char *s, int c)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> +
> + return __strchr(s, c);
> +}
> +EXPORT_SYMBOL(strchr);
> +
> +#undef strchrnul
> +char *strchrnul(const char *s, int c)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> +
> + return __strchrnul(s, c);
> +}
> +EXPORT_SYMBOL(strchrnul);
> +
> +#undef strrchr
> +char *strrchr(const char *s, int c)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> +
> + return __strrchr(s, c);
> +}
> +EXPORT_SYMBOL(strrchr);
> +
> +#undef strnchr
> +char *strnchr(const char *s, size_t count, int c)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> +
> + return __strnchr(s, count, c);
> +}
> +EXPORT_SYMBOL(strnchr);
> +
> +#undef skip_spaces
> +char *skip_spaces(const char *str)
> +{
> + size_t len = __strlen(str) + 1;
> +
> + check_memory_region((unsigned long)str, len, false, _RET_IP_);
> +
> + return __skip_spaces(str);
> +}
> +EXPORT_SYMBOL(skip_spaces);
> +
> +#undef strim
> +char *strim(char *s)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> +
> + return __strim(s);
> +}
> +EXPORT_SYMBOL(strim);
> +
> +#undef strstr
> +char *strstr(const char *s1, const char *s2)
> +{
> + size_t l1 = __strlen(s1) + 1;
> + size_t l2 = __strlen(s2) + 1;
> +
> + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
> + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
> +
> + return __strstr(s1, s2);
> +}
> +EXPORT_SYMBOL(strstr);
> +
> +#undef strnstr
> +char *strnstr(const char *s1, const char *s2, size_t len)
> +{
> + size_t l1 = min(__strlen(s1) + 1, len);
> + size_t l2 = __strlen(s2) + 1;
> +
> + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
> + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
> +
> + return __strnstr(s1, s2, len);
> +}
> +EXPORT_SYMBOL(strnstr);
> +
> +#undef strlen
> +size_t strlen(const char *s)
> +{
> + size_t len = __strlen(s);
> +
> + check_memory_region((unsigned long)s, len + 1, false, _RET_IP_);
> +
> + return len;
> +}
> +EXPORT_SYMBOL(strlen);
> +
> +#undef strnlen
> +size_t strnlen(const char *s, size_t count)
> +{
> + size_t len = __strnlen(s, count);
> +
> + check_memory_region((unsigned long)s, min(len + 1, count), false, _RET_IP_);
> +
> + return len;
> +}
> +EXPORT_SYMBOL(strnlen);
> +
> +#undef strpbrk
> +char *strpbrk(const char *cs, const char *ct)
> +{
> + size_t ls = __strlen(cs) + 1;
> + size_t lt = __strlen(ct) + 1;
> +
> + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
> + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
> +
> + return __strpbrk(cs, ct);
> +}
> +EXPORT_SYMBOL(strpbrk);
> +
> +#undef strsep
> +char *strsep(char **s, const char *ct)
> +{
> + char *cs = *s;
> +
> + check_memory_region((unsigned long)s, sizeof(*s), true, _RET_IP_);
> +
> + if (cs) {
> + int ls = __strlen(cs) + 1;
> + int lt = __strlen(ct) + 1;
> +
> + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
> + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
> + }
> +
> + return __strsep(s, ct);
> +}
> +EXPORT_SYMBOL(strsep);
> +
> +#undef strspn
> +size_t strspn(const char *s, const char *accept)
> +{
> + size_t ls = __strlen(s) + 1;
> + size_t la = __strlen(accept) + 1;
> +
> + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
> + check_memory_region((unsigned long)accept, la, false, _RET_IP_);
> +
> + return __strspn(s, accept);
> +}
> +EXPORT_SYMBOL(strspn);
> +
> +#undef strcspn
> +size_t strcspn(const char *s, const char *reject)
> +{
> + size_t ls = __strlen(s) + 1;
> + size_t lr = __strlen(reject) + 1;
> +
> + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
> + check_memory_region((unsigned long)reject, lr, false, _RET_IP_);
> +
> + return __strcspn(s, reject);
> +}
> +EXPORT_SYMBOL(strcspn);
> +
> +#undef memscan
> +void *memscan(void *addr, int c, size_t size)
> +{
> + check_memory_region((unsigned long)addr, size, false, _RET_IP_);
> +
> + return __memscan(addr, c, size);
> +}
> +EXPORT_SYMBOL(memscan);
> +
> +#undef memcmp
> +int memcmp(const void *cs, const void *ct, size_t count)
> +{
> + check_memory_region((unsigned long)cs, count, false, _RET_IP_);
> + check_memory_region((unsigned long)ct, count, false, _RET_IP_);
> +
> + return __memcmp(cs, ct, count);
> +}
> +EXPORT_SYMBOL(memcmp);
> +
> +#undef memchr
> +void *memchr(const void *s, int c, size_t n)
> +{
> + check_memory_region((unsigned long)s, n, false, _RET_IP_);
> +
> + return __memchr(s, c, n);
> +}
> +EXPORT_SYMBOL(memchr);
> +
> +#undef memchr_inv
> +void *memchr_inv(const void *start, int c, size_t bytes)
> +{
> + check_memory_region((unsigned long)start, bytes, false, _RET_IP_);
> +
> + return __memchr_inv(start, c, bytes);
> +}
> +EXPORT_SYMBOL(memchr_inv);
> +
> +#undef strreplace
> +char *strreplace(char *s, char old, char new)
> +{
> + size_t len = __strlen(s) + 1;
> +
> + check_memory_region((unsigned long)s, len, true, _RET_IP_);
> +
> + return __strreplace(s, old, new);
> +}
> +EXPORT_SYMBOL(strreplace);
>
^ permalink raw reply
* RE: [PATCH] ASoC: fsl_esai: Support synchronous mode
From: S.j. Wang @ 2019-04-02 10:16 UTC (permalink / raw)
To: Nicolin Chen
Cc: alsa-devel@alsa-project.org, timur@kernel.org,
Xiubo.Lee@gmail.com, festevam@gmail.com, broonie@kernel.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20190401181742.GA21288@Asurada-Nvidia>
Hi
>
> Shengjiu,
>
> On Mon, Apr 01, 2019 at 11:39:10AM +0000, S.j. Wang wrote:
> > In ESAI synchronous mode, the clock is generated by Tx, So we should
> > always set registers of Tx which relate with the bit clock and frame
> > clock generation (TCCR, TCR, ECR), even there is only Rx is working.
> >
> > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > ---
> > sound/soc/fsl/fsl_esai.c | 28 +++++++++++++++++++++++++++-
> > 1 file changed, 27 insertions(+), 1 deletion(-)
> >
> > diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index
> > 3623aa9a6f2e..d9fcddd55c02 100644
> > --- a/sound/soc/fsl/fsl_esai.c
> > +++ b/sound/soc/fsl/fsl_esai.c
> > @@ -230,6 +230,21 @@ static int fsl_esai_set_dai_sysclk(struct
> snd_soc_dai *dai, int clk_id,
> > return -EINVAL;
> > }
> >
> > + if (esai_priv->synchronous && !tx) {
> > + switch (clk_id) {
> > + case ESAI_HCKR_FSYS:
> > + fsl_esai_set_dai_sysclk(dai, ESAI_HCKT_FSYS,
> > + freq, dir);
> > + break;
> > + case ESAI_HCKR_EXTAL:
> > + fsl_esai_set_dai_sysclk(dai, ESAI_HCKT_EXTAL,
> > + freq, dir);
>
> Not sure why you call set_dai_sysclk inside set_dai_sysclk again. It feels very
> confusing to do so, especially without a comments.
For sync mode, only RX is enabled, the register of tx should be set, so call the
Set_dai_sysclk again.
>
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> > + }
> > +
> > /* Bypass divider settings if the requirement doesn't change */
> > if (freq == esai_priv->hck_rate[tx] && dir == esai_priv->hck_dir[tx])
> > return 0;
> > @@ -537,10 +552,21 @@ static int fsl_esai_hw_params(struct
> > snd_pcm_substream *substream,
> >
> > bclk = params_rate(params) * slot_width * esai_priv->slots;
> >
> > - ret = fsl_esai_set_bclk(dai, tx, bclk);
> > + ret = fsl_esai_set_bclk(dai, esai_priv->synchronous ? true : tx,
> > +bclk);
> > if (ret)
> > return ret;
> >
> > + if (esai_priv->synchronous && !tx) {
> > + /* Use Normal mode to support monaural audio */
> > + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
> > + ESAI_xCR_xMOD_MASK,
> params_channels(params) > 1 ?
> > + ESAI_xCR_xMOD_NETWORK : 0);
> > +
> > + mask = ESAI_xCR_xSWS_MASK | ESAI_xCR_PADC;
> > + val = ESAI_xCR_xSWS(slot_width, width) | ESAI_xCR_PADC;
> > + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
> mask, val);
> > + }
>
> Does synchronous mode require to set both TCR and RCR? or just TCR?
> The code behind this part is doing the same setting to RCR. If that is not
> needed any more for a synchronous recording, we should reuse it instead
> of inserting a piece of redundant code. Otherwise, if we need to set both,
> we should have two regmap_update_bits operations back-to-back for TCR
> and RCR (and other registers too).
Both TCR and RCR. RCR will be set in normal flow.
>
> > +
> > /* Use Normal mode to support monaural audio */
> > regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
> > ESAI_xCR_xMOD_MASK,
> params_channels(params) > 1 ?
>
> In case that we only need to set TCR (more likely I feel), it would feel less
> confusing to me, if we changed REG_ESAI_xCR(tx) here, for example, to
> REG_ESAI_xCR(tx || sync). Yea, please add to the top a 'bool sync =
> esai_priv->synchronous;'.
>
> Similarly, for ECR_ETO and ECR_ERO:
> (tx || sync) ? ESAI_ECR_ETO : ESAI_ECR_ERO;
Both TCR and RCR should be set.
^ permalink raw reply
* [PATCH v2 2/3] powernv/mce: Print correct severity for mce error.
From: Mahesh J Salgaonkar @ 2019-04-02 11:22 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Nicholas Piggin
In-Reply-To: <155420413881.2300.2285674976773307106.stgit@jupiter>
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Currently all machine check errors are printed as severe errors which isn't
correct. Print soft errors as warning instead of severe errors.
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
change in v2:
- Use kernel types i.e. u8, u64 etc.
- Define sync_error as bool.
---
arch/powerpc/include/asm/mce.h | 86 ++++++++++----------
arch/powerpc/kernel/mce.c | 5 +
arch/powerpc/kernel/mce_power.c | 144 +++++++++++++++++----------------
arch/powerpc/platforms/powernv/opal.c | 2
4 files changed, 123 insertions(+), 114 deletions(-)
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 8d0b1c24c636..b1f4bf863c95 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -31,7 +31,7 @@ enum MCE_Version {
enum MCE_Severity {
MCE_SEV_NO_ERROR = 0,
MCE_SEV_WARNING = 1,
- MCE_SEV_ERROR_SYNC = 2,
+ MCE_SEV_SEVERE = 2,
MCE_SEV_FATAL = 3,
};
@@ -110,73 +110,74 @@ enum MCE_LinkErrorType {
};
struct machine_check_event {
- enum MCE_Version version:8; /* 0x00 */
- uint8_t in_use; /* 0x01 */
- enum MCE_Severity severity:8; /* 0x02 */
- enum MCE_Initiator initiator:8; /* 0x03 */
- enum MCE_ErrorType error_type:8; /* 0x04 */
- enum MCE_Disposition disposition:8; /* 0x05 */
- uint16_t cpu; /* 0x06 */
- uint64_t gpr3; /* 0x08 */
- uint64_t srr0; /* 0x10 */
- uint64_t srr1; /* 0x18 */
- union { /* 0x20 */
+ enum MCE_Version version:8;
+ u8 in_use;
+ enum MCE_Severity severity:8;
+ enum MCE_Initiator initiator:8;
+ enum MCE_ErrorType error_type:8;
+ enum MCE_Disposition disposition:8;
+ bool sync_error;
+ u16 cpu;
+ u64 gpr3;
+ u64 srr0;
+ u64 srr1;
+ union {
struct {
enum MCE_UeErrorType ue_error_type:8;
- uint8_t effective_address_provided;
- uint8_t physical_address_provided;
- uint8_t reserved_1[5];
- uint64_t effective_address;
- uint64_t physical_address;
- uint8_t reserved_2[8];
+ u8 effective_address_provided;
+ u8 physical_address_provided;
+ u8 reserved_1[5];
+ u64 effective_address;
+ u64 physical_address;
+ u8 reserved_2[8];
} ue_error;
struct {
enum MCE_SlbErrorType slb_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} slb_error;
struct {
enum MCE_EratErrorType erat_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} erat_error;
struct {
enum MCE_TlbErrorType tlb_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} tlb_error;
struct {
enum MCE_UserErrorType user_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} user_error;
struct {
enum MCE_RaErrorType ra_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} ra_error;
struct {
enum MCE_LinkErrorType link_error_type:8;
- uint8_t effective_address_provided;
- uint8_t reserved_1[6];
- uint64_t effective_address;
- uint8_t reserved_2[16];
+ u8 effective_address_provided;
+ u8 reserved_1[6];
+ u64 effective_address;
+ u8 reserved_2[16];
} link_error;
} u;
};
@@ -194,6 +195,7 @@ struct mce_error_info {
} u;
enum MCE_Severity severity:8;
enum MCE_Initiator initiator:8;
+ bool sync_error;
};
#define MAX_MC_EVT 100
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index d3ee099e0981..0f961583bd51 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -122,6 +122,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
mce->initiator = mce_err->initiator;
mce->severity = mce_err->severity;
+ mce->sync_error = mce_err->sync_error;
/*
* Populate the mce error_type and type-specific error_type.
@@ -374,9 +375,9 @@ void machine_check_print_event_info(struct machine_check_event *evt,
break;
case MCE_SEV_WARNING:
level = KERN_WARNING;
- sevstr = "";
+ sevstr = "Warning";
break;
- case MCE_SEV_ERROR_SYNC:
+ case MCE_SEV_SEVERE:
level = KERN_ERR;
sevstr = "Severe";
break;
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 6b800eec31f2..606af87a4dda 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -133,106 +133,107 @@ struct mce_ierror_table {
unsigned int error_subtype;
unsigned int initiator;
unsigned int severity;
+ bool sync_error;
};
static const struct mce_ierror_table mce_p7_ierror_table[] = {
{ 0x00000000001c0000, 0x0000000000040000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x0000000000080000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x00000000000c0000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000100000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000140000, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000180000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x00000000001c0000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, 0, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
+{ 0, 0, 0, 0, 0, 0, 0 } };
static const struct mce_ierror_table mce_p8_ierror_table[] = {
{ 0x00000000081c0000, 0x0000000000040000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000000080000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000000c0000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000100000, true,
MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000140000, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000180000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000001c0000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008000000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008040000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, 0, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
+{ 0, 0, 0, 0, 0, 0, 0 } };
static const struct mce_ierror_table mce_p9_ierror_table[] = {
{ 0x00000000081c0000, 0x0000000000040000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000000080000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000000c0000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000100000, true,
MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000140000, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000180000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000001c0000, true,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008000000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008040000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000080c0000, true,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008100000, true,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008140000, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_FATAL, }, /* ASYNC is fatal */
+ MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
{ 0x00000000081c0000, 0x0000000008180000, false,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_FATAL, }, /* ASYNC is fatal */
+ MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
{ 0x00000000081c0000, 0x00000000081c0000, true,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, 0, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
+{ 0, 0, 0, 0, 0, 0, 0 } };
struct mce_derror_table {
unsigned long dsisr_value;
@@ -241,103 +242,104 @@ struct mce_derror_table {
unsigned int error_subtype;
unsigned int initiator;
unsigned int severity;
+ bool sync_error;
};
static const struct mce_derror_table mce_p7_derror_table[] = {
{ 0x00008000, false,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000040, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, false, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
+{ 0, false, 0, 0, 0, 0, 0 } };
static const struct mce_derror_table mce_p8_derror_table[] = {
{ 0x00008000, false,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00002000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00001000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000200, true,
MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, /* SECONDARY ERAT */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, false, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
+{ 0, false, 0, 0, 0, 0, 0 } };
static const struct mce_derror_table mce_p9_derror_table[] = {
{ 0x00008000, false,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00002000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00001000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000200, false,
MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000040, true,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000020, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000010, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000008, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN,
- MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
-{ 0, false, 0, 0, 0, 0 } };
+ MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
+{ 0, false, 0, 0, 0, 0, 0 } };
static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr,
uint64_t *phys_addr)
@@ -427,11 +429,12 @@ static int mce_handle_ierror(struct pt_regs *regs,
mce_err->u.link_error_type = table[i].error_subtype;
break;
}
+ mce_err->sync_error = table[i].sync_error;
mce_err->severity = table[i].severity;
mce_err->initiator = table[i].initiator;
if (table[i].nip_valid) {
*addr = regs->nip;
- if (mce_err->severity == MCE_SEV_ERROR_SYNC &&
+ if (mce_err->sync_error &&
table[i].error_type == MCE_ERROR_TYPE_UE) {
unsigned long pfn;
@@ -448,8 +451,9 @@ static int mce_handle_ierror(struct pt_regs *regs,
}
mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
- mce_err->severity = MCE_SEV_ERROR_SYNC;
+ mce_err->severity = MCE_SEV_SEVERE;
mce_err->initiator = MCE_INITIATOR_CPU;
+ mce_err->sync_error = true;
return 0;
}
@@ -519,11 +523,12 @@ static int mce_handle_derror(struct pt_regs *regs,
mce_err->u.link_error_type = table[i].error_subtype;
break;
}
+ mce_err->sync_error = table[i].sync_error;
mce_err->severity = table[i].severity;
mce_err->initiator = table[i].initiator;
if (table[i].dar_valid)
*addr = regs->dar;
- else if (mce_err->severity == MCE_SEV_ERROR_SYNC &&
+ else if (mce_err->sync_error &&
table[i].error_type == MCE_ERROR_TYPE_UE) {
/*
* We do a maximum of 4 nested MCE calls, see
@@ -539,8 +544,9 @@ static int mce_handle_derror(struct pt_regs *regs,
return handled;
mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
- mce_err->severity = MCE_SEV_ERROR_SYNC;
+ mce_err->severity = MCE_SEV_SEVERE;
mce_err->initiator = MCE_INITIATOR_CPU;
+ mce_err->sync_error = true;
return 0;
}
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 77552e525e33..f2b063b027f0 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -505,7 +505,7 @@ static int opal_recover_mce(struct pt_regs *regs,
recovered = 0;
}
- if (!recovered && evt->severity == MCE_SEV_ERROR_SYNC) {
+ if (!recovered && evt->sync_error) {
/*
* Try to kill processes if we get a synchronous machine check
* (e.g., one caused by execution of this instruction). This
^ permalink raw reply related
* [PATCH v2 1/3] powernv/mce: reduce mce console logs to lesser lines.
From: Mahesh J Salgaonkar @ 2019-04-02 11:22 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Nicholas Piggin
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Also add cpu number while displaying mce log. This will help cleaner logs
when mce hits on multiple cpus simultaneously.
before the changes the mce o/p was:
[ 127.223515] Severe Machine check interrupt [Recovered]
[ 127.223530] NIP [d00000000ba80280]: insert_slb_entry.constprop.0+0x278/0x2c0 [mcetest_slb]
[ 127.223539] Initiator: CPU
[ 127.223544] Error type: SLB [Multihit]
[ 127.223550] Effective address: d00000000ba80280
After this patch series changes the mce o/p will be:
[ 471.959843] MCE: CPU80: machine check (Warning) Host SLB Multihit [Recovered]
[ 471.959870] MCE: CPU80: NIP: [d00000000b550280] insert_slb_entry.constprop.0+0x278/0x2c0 [mcetest_slb]
[ 471.959892] MCE: CPU80: Probable software error (some chance of hardware cause)
and for MCE in Guest:
[ 1289.447571] MCE: CPU80: machine check (Warning) Guest SLB Multihit DAR: 000001001b6e0320 [Recovered]
[ 1289.447615] MCE: CPU80: PID: 24765 Comm: qemu-system-ppc Guest NIP: [00007fffa309dc60]
[ 1289.447634] MCE: CPU80: Probable software error (some chance of hardware cause)
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
Change in v2:
- Address comments from Michael.
---
arch/powerpc/include/asm/mce.h | 2 -
arch/powerpc/kernel/mce.c | 82 ++++++++++++++++++++--------------------
2 files changed, 41 insertions(+), 43 deletions(-)
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 17996bc9382b..8d0b1c24c636 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -116,7 +116,7 @@ struct machine_check_event {
enum MCE_Initiator initiator:8; /* 0x03 */
enum MCE_ErrorType error_type:8; /* 0x04 */
enum MCE_Disposition disposition:8; /* 0x05 */
- uint8_t reserved_1[2]; /* 0x06 */
+ uint16_t cpu; /* 0x06 */
uint64_t gpr3; /* 0x08 */
uint64_t srr0; /* 0x10 */
uint64_t srr1; /* 0x18 */
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index b5fec1f9751a..d3ee099e0981 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -112,6 +112,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
mce->srr1 = regs->msr;
mce->gpr3 = regs->gpr[3];
mce->in_use = 1;
+ mce->cpu = get_paca()->paca_index;
/* Mark it recovered if we have handled it and MSR(RI=1). */
if (handled && (regs->msr & MSR_RI))
@@ -310,7 +311,9 @@ static void machine_check_process_queued_event(struct irq_work *work)
void machine_check_print_event_info(struct machine_check_event *evt,
bool user_mode, bool in_guest)
{
- const char *level, *sevstr, *subtype;
+ const char *level, *sevstr, *subtype, *err_type;
+ uint64_t ea = 0;
+ char dar_str[50];
static const char *mc_ue_types[] = {
"Indeterminate",
"Instruction fetch",
@@ -384,101 +387,96 @@ void machine_check_print_event_info(struct machine_check_event *evt,
break;
}
- printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
- evt->disposition == MCE_DISPOSITION_RECOVERED ?
- "Recovered" : "Not recovered");
-
- if (in_guest) {
- printk("%s Guest NIP: %016llx\n", level, evt->srr0);
- } else if (user_mode) {
- printk("%s NIP: [%016llx] PID: %d Comm: %s\n", level,
- evt->srr0, current->pid, current->comm);
- } else {
- printk("%s NIP [%016llx]: %pS\n", level, evt->srr0,
- (void *)evt->srr0);
- }
-
- printk("%s Initiator: %s\n", level,
- evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown");
switch (evt->error_type) {
case MCE_ERROR_TYPE_UE:
+ err_type = "UE";
subtype = evt->u.ue_error.ue_error_type <
ARRAY_SIZE(mc_ue_types) ?
mc_ue_types[evt->u.ue_error.ue_error_type]
: "Unknown";
- printk("%s Error type: UE [%s]\n", level, subtype);
if (evt->u.ue_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.ue_error.effective_address);
- if (evt->u.ue_error.physical_address_provided)
- printk("%s Physical address: %016llx\n",
- level, evt->u.ue_error.physical_address);
+ ea = evt->u.ue_error.effective_address;
break;
case MCE_ERROR_TYPE_SLB:
+ err_type = "SLB";
subtype = evt->u.slb_error.slb_error_type <
ARRAY_SIZE(mc_slb_types) ?
mc_slb_types[evt->u.slb_error.slb_error_type]
: "Unknown";
- printk("%s Error type: SLB [%s]\n", level, subtype);
if (evt->u.slb_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.slb_error.effective_address);
+ ea = evt->u.slb_error.effective_address;
break;
case MCE_ERROR_TYPE_ERAT:
+ err_type = "ERAT";
subtype = evt->u.erat_error.erat_error_type <
ARRAY_SIZE(mc_erat_types) ?
mc_erat_types[evt->u.erat_error.erat_error_type]
: "Unknown";
- printk("%s Error type: ERAT [%s]\n", level, subtype);
if (evt->u.erat_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.erat_error.effective_address);
+ ea = evt->u.erat_error.effective_address;
break;
case MCE_ERROR_TYPE_TLB:
+ err_type = "TLB";
subtype = evt->u.tlb_error.tlb_error_type <
ARRAY_SIZE(mc_tlb_types) ?
mc_tlb_types[evt->u.tlb_error.tlb_error_type]
: "Unknown";
- printk("%s Error type: TLB [%s]\n", level, subtype);
if (evt->u.tlb_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.tlb_error.effective_address);
+ ea = evt->u.tlb_error.effective_address;
break;
case MCE_ERROR_TYPE_USER:
+ err_type = "User";
subtype = evt->u.user_error.user_error_type <
ARRAY_SIZE(mc_user_types) ?
mc_user_types[evt->u.user_error.user_error_type]
: "Unknown";
- printk("%s Error type: User [%s]\n", level, subtype);
if (evt->u.user_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.user_error.effective_address);
+ ea = evt->u.user_error.effective_address;
break;
case MCE_ERROR_TYPE_RA:
+ err_type = "Real address";
subtype = evt->u.ra_error.ra_error_type <
ARRAY_SIZE(mc_ra_types) ?
mc_ra_types[evt->u.ra_error.ra_error_type]
: "Unknown";
- printk("%s Error type: Real address [%s]\n", level, subtype);
if (evt->u.ra_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.ra_error.effective_address);
+ ea = evt->u.ra_error.effective_address;
break;
case MCE_ERROR_TYPE_LINK:
+ err_type = "Link";
subtype = evt->u.link_error.link_error_type <
ARRAY_SIZE(mc_link_types) ?
mc_link_types[evt->u.link_error.link_error_type]
: "Unknown";
- printk("%s Error type: Link [%s]\n", level, subtype);
if (evt->u.link_error.effective_address_provided)
- printk("%s Effective address: %016llx\n",
- level, evt->u.link_error.effective_address);
+ ea = evt->u.link_error.effective_address;
break;
default:
case MCE_ERROR_TYPE_UNKNOWN:
- printk("%s Error type: Unknown\n", level);
+ err_type = "Unknown";
+ subtype = "";
break;
}
+
+ if (ea && evt->srr0 != ea)
+ sprintf(dar_str, "DAR: %016llx ", ea);
+ else
+ dar_str[0] = '\0';
+
+ printk("%sMCE: CPU%d: machine check (%s) %s %s %s %s[%s]\n",
+ level, evt->cpu, sevstr, in_guest ? "Guest" : "Host",
+ err_type, subtype, dar_str,
+ evt->disposition == MCE_DISPOSITION_RECOVERED ?
+ "Recovered" : "Not recovered");
+
+ if (in_guest || user_mode) {
+ printk("%sMCE: CPU%d: PID: %d Comm: %s %sNIP: [%016llx]\n",
+ level, evt->cpu, current->pid, current->comm,
+ in_guest ? "Guest " : "", evt->srr0);
+ } else {
+ printk("%sMCE: CPU%d: NIP: [%016llx] %pS\n",
+ level, evt->cpu, evt->srr0, (void *)evt->srr0);
+ }
}
EXPORT_SYMBOL_GPL(machine_check_print_event_info);
^ permalink raw reply related
* [PATCH] powerpc/watchdog: Use hrtimers for per-CPU heartbeat
From: Nicholas Piggin @ 2019-04-02 11:25 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Ravikumar Bangoria, Nicholas Piggin
Using a jiffies timer creates a dependency on the tick_do_timer_cpu
incrementing jiffies. If that CPU has locked up and jiffies is not
incrementing, the watchdog heartbeat timer for all CPUs stops and
creates false positives and confusing warnings on local CPUs, and
also causes the SMP detector to stop, so the root cause is never
detected.
Fix this by using hrtimer based timers for the watchdog heartbeat,
like the generic kernel hardlockup detector.
Reported-by: Ravikumar Bangoria <ravi.bangoria@in.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
arch/powerpc/kernel/watchdog.c | 34 ++++++++++++++++++----------------
1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c
index 3c6ab22a0c4e..59a0e5942f6b 100644
--- a/arch/powerpc/kernel/watchdog.c
+++ b/arch/powerpc/kernel/watchdog.c
@@ -77,7 +77,7 @@ static u64 wd_smp_panic_timeout_tb __read_mostly; /* panic other CPUs */
static u64 wd_timer_period_ms __read_mostly; /* interval between heartbeat */
-static DEFINE_PER_CPU(struct timer_list, wd_timer);
+static DEFINE_PER_CPU(struct hrtimer, wd_hrtimer);
static DEFINE_PER_CPU(u64, wd_timer_tb);
/* SMP checker bits */
@@ -293,21 +293,21 @@ void soft_nmi_interrupt(struct pt_regs *regs)
nmi_exit();
}
-static void wd_timer_reset(unsigned int cpu, struct timer_list *t)
-{
- t->expires = jiffies + msecs_to_jiffies(wd_timer_period_ms);
- if (wd_timer_period_ms > 1000)
- t->expires = __round_jiffies_up(t->expires, cpu);
- add_timer_on(t, cpu);
-}
-
-static void wd_timer_fn(struct timer_list *t)
+static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
{
int cpu = smp_processor_id();
+ if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED))
+ return HRTIMER_NORESTART;
+
+ if (!cpumask_test_cpu(cpu, &watchdog_cpumask))
+ return HRTIMER_NORESTART;
+
watchdog_timer_interrupt(cpu);
- wd_timer_reset(cpu, t);
+ hrtimer_forward_now(hrtimer, ms_to_ktime(wd_timer_period_ms));
+
+ return HRTIMER_RESTART;
}
void arch_touch_nmi_watchdog(void)
@@ -325,19 +325,21 @@ EXPORT_SYMBOL(arch_touch_nmi_watchdog);
static void start_watchdog_timer_on(unsigned int cpu)
{
- struct timer_list *t = per_cpu_ptr(&wd_timer, cpu);
+ struct hrtimer *hrtimer = this_cpu_ptr(&wd_hrtimer);
per_cpu(wd_timer_tb, cpu) = get_tb();
- timer_setup(t, wd_timer_fn, TIMER_PINNED);
- wd_timer_reset(cpu, t);
+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer->function = watchdog_timer_fn;
+ hrtimer_start(hrtimer, ms_to_ktime(wd_timer_period_ms),
+ HRTIMER_MODE_REL_PINNED);
}
static void stop_watchdog_timer_on(unsigned int cpu)
{
- struct timer_list *t = per_cpu_ptr(&wd_timer, cpu);
+ struct hrtimer *hrtimer = this_cpu_ptr(&wd_hrtimer);
- del_timer_sync(t);
+ hrtimer_cancel(hrtimer);
}
static int start_wd_on_cpu(unsigned int cpu)
--
2.20.1
^ permalink raw reply related
* [PATCH v2 3/3] powernv/mce: print additional information about mce error.
From: Mahesh J Salgaonkar @ 2019-04-02 11:23 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Paul Mackerras, Nicholas Piggin
In-Reply-To: <155420413881.2300.2285674976773307106.stgit@jupiter>
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Print more information about mce error whether it is an hardware or
software error.
Some of the mce errors can be easily categorized as hardware or software
errors e.g. UEs are due to hardware error, where as error triggered due to
invalid usage of tlbie is a pure software bug. But not all the mce errors
can be easily categorize into either software or hardware. There are errors
like multihit errors which are usually result of a software bug, but in
some rare cases a hardware failure can cause a multihit error. In past, we
have seen case where after replacing faulty chip, multihit errors stopped
occurring. Same with parity errors, which are usually due to faulty hardware
but there are chances where multihit can also cause an parity error. Such
errors are difficult to determine what really caused it. Hence this patch
classifies mce errors into following four categorize:
1. Hardware error:
UE and Link timeout failure errors.
2. Probable hardware error (some chance of software cause)
SLB/ERAT/TLB Parity errors.
3. Software error
Invalid tlbie form.
4. Probable software error (some chance of hardware cause)
SLB/ERAT/TLB Multihit errors.
Sample o/p:
[ 1289.447571] MCE: CPU80: machine check (Warning) Guest SLB Multihit DAR: 000001001b6e0320 [Recovered]
[ 1289.447615] MCE: CPU80: PID: 24765 Comm: qemu-system-ppc Guest NIP: [00007fffa309dc60]
[ 1289.447634] MCE: CPU80: Probable Software error (some chance of hardware cause)
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
---
Change in v2:
- Rephrase the wording for error class as suggested by Michael.
---
arch/powerpc/include/asm/mce.h | 10 ++++
arch/powerpc/kernel/mce.c | 12 ++++
arch/powerpc/kernel/mce_power.c | 107 +++++++++++++++++++++++----------------
3 files changed, 86 insertions(+), 43 deletions(-)
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index b1f4bf863c95..8741f4c21a1a 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -56,6 +56,14 @@ enum MCE_ErrorType {
MCE_ERROR_TYPE_LINK = 7,
};
+enum MCE_ErrorClass {
+ MCE_ECLASS_UNKNOWN = 0,
+ MCE_ECLASS_HARDWARE,
+ MCE_ECLASS_HARD_INDETERMINATE,
+ MCE_ECLASS_SOFTWARE,
+ MCE_ECLASS_SOFT_INDETERMINATE,
+};
+
enum MCE_UeErrorType {
MCE_UE_ERROR_INDETERMINATE = 0,
MCE_UE_ERROR_IFETCH = 1,
@@ -115,6 +123,7 @@ struct machine_check_event {
enum MCE_Severity severity:8;
enum MCE_Initiator initiator:8;
enum MCE_ErrorType error_type:8;
+ enum MCE_ErrorClass error_class:8;
enum MCE_Disposition disposition:8;
bool sync_error;
u16 cpu;
@@ -195,6 +204,7 @@ struct mce_error_info {
} u;
enum MCE_Severity severity:8;
enum MCE_Initiator initiator:8;
+ enum MCE_ErrorClass error_class:8;
bool sync_error;
};
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index 0f961583bd51..1d978c3477a0 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -123,6 +123,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
mce->initiator = mce_err->initiator;
mce->severity = mce_err->severity;
mce->sync_error = mce_err->sync_error;
+ mce->error_class = mce_err->error_class;
/*
* Populate the mce error_type and type-specific error_type.
@@ -361,6 +362,13 @@ void machine_check_print_event_info(struct machine_check_event *evt,
"Store (timeout)",
"Page table walk Load/Store (timeout)",
};
+ static const char *mc_error_class[] = {
+ "Unknown",
+ "Hardware error",
+ "Probable Hardware error (some chance of software cause)",
+ "Software error",
+ "Probable Software error (some chance of hardware cause)",
+ };
/* Print things out */
if (evt->version != MCE_V1) {
@@ -478,6 +486,10 @@ void machine_check_print_event_info(struct machine_check_event *evt,
printk("%sMCE: CPU%d: NIP: [%016llx] %pS\n",
level, evt->cpu, evt->srr0, (void *)evt->srr0);
}
+
+ subtype = evt->error_class < ARRAY_SIZE(mc_error_class) ?
+ mc_error_class[evt->error_class] : "Unknown";
+ printk("%sMCE: CPU%d: %s\n", level, evt->cpu, subtype);
}
EXPORT_SYMBOL_GPL(machine_check_print_event_info);
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 606af87a4dda..3658af85e48a 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -131,6 +131,7 @@ struct mce_ierror_table {
bool nip_valid; /* nip is a valid indicator of faulting address */
unsigned int error_type;
unsigned int error_subtype;
+ unsigned int error_class;
unsigned int initiator;
unsigned int severity;
bool sync_error;
@@ -138,99 +139,103 @@ struct mce_ierror_table {
static const struct mce_ierror_table mce_p7_ierror_table[] = {
{ 0x00000000001c0000, 0x0000000000040000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x0000000000080000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x00000000000c0000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000100000, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
+ MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000140000, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000001c0000, 0x0000000000180000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000001c0000, 0x00000000001c0000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0, 0, 0, 0, 0, 0, 0 } };
static const struct mce_ierror_table mce_p8_ierror_table[] = {
{ 0x00000000081c0000, 0x0000000000040000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000000080000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000000c0000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000100000, true,
- MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000140000, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000180000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000001c0000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008000000, true,
- MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
+ MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008040000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0, 0, 0, 0, 0, 0, 0 } };
static const struct mce_ierror_table mce_p9_ierror_table[] = {
{ 0x00000000081c0000, 0x0000000000040000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000000080000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000000c0000, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000100000, true,
- MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000140000, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000000081c0000, 0x0000000000180000, true,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000001c0000, true,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008000000, true,
- MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
+ MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008040000, true,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x00000000080c0000, true,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008100000, true,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000000081c0000, 0x0000000008140000, false,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
{ 0x00000000081c0000, 0x0000000008180000, false,
MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
MCE_INITIATOR_CPU, MCE_SEV_FATAL, false }, /* ASYNC is fatal */
-{ 0x00000000081c0000, 0x00000000081c0000, true,
+{ 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0, 0, 0, 0, 0, 0, 0 } };
@@ -240,6 +245,7 @@ struct mce_derror_table {
bool dar_valid; /* dar is a valid indicator of faulting address */
unsigned int error_type;
unsigned int error_subtype;
+ unsigned int error_class;
unsigned int initiator;
unsigned int severity;
bool sync_error;
@@ -247,97 +253,108 @@ struct mce_derror_table {
static const struct mce_derror_table mce_p7_derror_table[] = {
{ 0x00008000, false,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
- MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000040, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
+ MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0, false, 0, 0, 0, 0, 0 } };
static const struct mce_derror_table mce_p8_derror_table[] = {
{ 0x00008000, false,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00002000, true,
- MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
+ MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00001000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
- MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000200, true,
MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, /* SECONDARY ERAT */
+ MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
+ MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0, false, 0, 0, 0, 0, 0 } };
static const struct mce_derror_table mce_p9_derror_table[] = {
{ 0x00008000, false,
- MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
+ MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00004000, true,
MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00002000, true,
- MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
+ MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00001000, true,
MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000800, true,
- MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000400, true,
- MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
+ MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000200, false,
- MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE,
+ MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000080, true,
MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, /* Before PARITY */
+ MCE_ECLASS_SOFT_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
{ 0x00000100, true,
- MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
+ MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000040, true,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000020, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000010, false,
MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
+ MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0x00000008, false,
- MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN,
+ MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
{ 0, false, 0, 0, 0, 0, 0 } };
@@ -406,6 +423,7 @@ static int mce_handle_ierror(struct pt_regs *regs,
/* now fill in mce_error_info */
mce_err->error_type = table[i].error_type;
+ mce_err->error_class = table[i].error_class;
switch (table[i].error_type) {
case MCE_ERROR_TYPE_UE:
mce_err->u.ue_error_type = table[i].error_subtype;
@@ -451,6 +469,7 @@ static int mce_handle_ierror(struct pt_regs *regs,
}
mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
+ mce_err->error_class = MCE_ECLASS_UNKNOWN;
mce_err->severity = MCE_SEV_SEVERE;
mce_err->initiator = MCE_INITIATOR_CPU;
mce_err->sync_error = true;
@@ -500,6 +519,7 @@ static int mce_handle_derror(struct pt_regs *regs,
/* now fill in mce_error_info */
mce_err->error_type = table[i].error_type;
+ mce_err->error_class = table[i].error_class;
switch (table[i].error_type) {
case MCE_ERROR_TYPE_UE:
mce_err->u.ue_error_type = table[i].error_subtype;
@@ -544,6 +564,7 @@ static int mce_handle_derror(struct pt_regs *regs,
return handled;
mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
+ mce_err->error_class = MCE_ECLASS_UNKNOWN;
mce_err->severity = MCE_SEV_SEVERE;
mce_err->initiator = MCE_INITIATOR_CPU;
mce_err->sync_error = true;
^ permalink raw reply related
* [PATCH v2] mm: Fix modifying of page protection by insert_pfn_pmd()
From: Aneesh Kumar K.V @ 2019-04-02 11:51 UTC (permalink / raw)
To: dan.j.williams, akpm, Jan Kara
Cc: linux-nvdimm, Aneesh Kumar K.V, stable, linux-mm,
Chandan Rajendra, linuxppc-dev
With some architectures like ppc64, set_pmd_at() cannot cope with
a situation where there is already some (different) valid entry present.
Use pmdp_set_access_flags() instead to modify the pfn which is built to
deal with modifying existing PMD entries.
This is similar to
commit cae85cb8add3 ("mm/memory.c: fix modifying of page protection by insert_pfn()")
We also do similar update w.r.t insert_pfn_pud eventhough ppc64 don't support
pud pfn entries now.
Without this patch we also see the below message in kernel log
"BUG: non-zero pgtables_bytes on freeing mm:"
CC: stable@vger.kernel.org
Reported-by: Chandan Rajendra <chandan@linux.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
Changes from v1:
* Fix the pgtable leak
mm/huge_memory.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 404acdcd0455..165ea46bf149 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -755,6 +755,21 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
spinlock_t *ptl;
ptl = pmd_lock(mm, pmd);
+ if (!pmd_none(*pmd)) {
+ if (write) {
+ if (pmd_pfn(*pmd) != pfn_t_to_pfn(pfn)) {
+ WARN_ON_ONCE(!is_huge_zero_pmd(*pmd));
+ goto out_unlock;
+ }
+ entry = pmd_mkyoung(*pmd);
+ entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
+ if (pmdp_set_access_flags(vma, addr, pmd, entry, 1))
+ update_mmu_cache_pmd(vma, addr, pmd);
+ }
+
+ goto out_unlock;
+ }
+
entry = pmd_mkhuge(pfn_t_pmd(pfn, prot));
if (pfn_t_devmap(pfn))
entry = pmd_mkdevmap(entry);
@@ -766,11 +781,16 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
if (pgtable) {
pgtable_trans_huge_deposit(mm, pmd, pgtable);
mm_inc_nr_ptes(mm);
+ pgtable = NULL;
}
set_pmd_at(mm, addr, pmd, entry);
update_mmu_cache_pmd(vma, addr, pmd);
+
+out_unlock:
spin_unlock(ptl);
+ if (pgtable)
+ pte_free(mm, pgtable);
}
vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
@@ -821,6 +841,20 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
spinlock_t *ptl;
ptl = pud_lock(mm, pud);
+ if (!pud_none(*pud)) {
+ if (write) {
+ if (pud_pfn(*pud) != pfn_t_to_pfn(pfn)) {
+ WARN_ON_ONCE(!is_huge_zero_pud(*pud));
+ goto out_unlock;
+ }
+ entry = pud_mkyoung(*pud);
+ entry = maybe_pud_mkwrite(pud_mkdirty(entry), vma);
+ if (pudp_set_access_flags(vma, addr, pud, entry, 1))
+ update_mmu_cache_pud(vma, addr, pud);
+ }
+ goto out_unlock;
+ }
+
entry = pud_mkhuge(pfn_t_pud(pfn, prot));
if (pfn_t_devmap(pfn))
entry = pud_mkdevmap(entry);
@@ -830,6 +864,8 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
}
set_pud_at(mm, addr, pud, entry);
update_mmu_cache_pud(vma, addr, pud);
+
+out_unlock:
spin_unlock(ptl);
}
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox