From: Greg Kroah-Hartman Date: Thu, 21 Sep 2017 11:01:17 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v3.18.72~34 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=215da057b3dd525cb148053439e6abdd25a131bf;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: pinctrl-amd-save-pin-registers-over-suspend-resume.patch tty-improve-tty_insert_flip_char-fast-path.patch --- diff --git a/queue-4.4/pinctrl-amd-save-pin-registers-over-suspend-resume.patch b/queue-4.4/pinctrl-amd-save-pin-registers-over-suspend-resume.patch new file mode 100644 index 00000000000..0b4c735baa8 --- /dev/null +++ b/queue-4.4/pinctrl-amd-save-pin-registers-over-suspend-resume.patch @@ -0,0 +1,148 @@ +From 79d2c8bede2c93f9432d7da0bc2f76a195c90fc0 Mon Sep 17 00:00:00 2001 +From: Daniel Drake +Date: Mon, 11 Sep 2017 14:11:56 +0800 +Subject: pinctrl/amd: save pin registers over suspend/resume + +From: Daniel Drake + +commit 79d2c8bede2c93f9432d7da0bc2f76a195c90fc0 upstream. + +The touchpad in the Asus laptop models X505BA/BP and X542BA/BP is +unresponsive after suspend/resume. The following error appears during +resume: + + i2c_hid i2c-ELAN1300:00: failed to reset device. + +The problem here is that i2c_hid does not notice the interrupt being +generated at this point, because the GPIO is no longer configured +for interrupts. + +Fix this by saving pinctrl-amd pin registers during suspend and +restoring them at resume time. + +Based on code from pinctrl-intel. + +Signed-off-by: Daniel Drake +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pinctrl/pinctrl-amd.c | 75 ++++++++++++++++++++++++++++++++++++++++++ + drivers/pinctrl/pinctrl-amd.h | 1 + 2 files changed, 76 insertions(+) + +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -32,6 +32,7 @@ + #include + #include + ++#include "core.h" + #include "pinctrl-utils.h" + #include "pinctrl-amd.h" + +@@ -708,6 +709,69 @@ static const struct pinconf_ops amd_pinc + .pin_config_group_set = amd_pinconf_group_set, + }; + ++#ifdef CONFIG_PM_SLEEP ++static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) ++{ ++ const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); ++ ++ if (!pd) ++ return false; ++ ++ /* ++ * Only restore the pin if it is actually in use by the kernel (or ++ * by userspace). ++ */ ++ if (pd->mux_owner || pd->gpio_owner || ++ gpiochip_line_is_irq(&gpio_dev->gc, pin)) ++ return true; ++ ++ return false; ++} ++ ++int amd_gpio_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); ++ struct pinctrl_desc *desc = gpio_dev->pctrl->desc; ++ int i; ++ ++ for (i = 0; i < desc->npins; i++) { ++ int pin = desc->pins[i].number; ++ ++ if (!amd_gpio_should_save(gpio_dev, pin)) ++ continue; ++ ++ gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4); ++ } ++ ++ return 0; ++} ++ ++int amd_gpio_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); ++ struct pinctrl_desc *desc = gpio_dev->pctrl->desc; ++ int i; ++ ++ for (i = 0; i < desc->npins; i++) { ++ int pin = desc->pins[i].number; ++ ++ if (!amd_gpio_should_save(gpio_dev, pin)) ++ continue; ++ ++ writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops amd_gpio_pm_ops = { ++ SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend, ++ amd_gpio_resume) ++}; ++#endif ++ + static struct pinctrl_desc amd_pinctrl_desc = { + .pins = kerncz_pins, + .npins = ARRAY_SIZE(kerncz_pins), +@@ -747,6 +811,14 @@ static int amd_gpio_probe(struct platfor + return -EINVAL; + } + ++#ifdef CONFIG_PM_SLEEP ++ gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, ++ sizeof(*gpio_dev->saved_regs), ++ GFP_KERNEL); ++ if (!gpio_dev->saved_regs) ++ return -ENOMEM; ++#endif ++ + gpio_dev->pdev = pdev; + gpio_dev->gc.direction_input = amd_gpio_direction_input; + gpio_dev->gc.direction_output = amd_gpio_direction_output; +@@ -837,6 +909,9 @@ static struct platform_driver amd_gpio_d + .driver = { + .name = "amd_gpio", + .acpi_match_table = ACPI_PTR(amd_gpio_acpi_match), ++#ifdef CONFIG_PM_SLEEP ++ .pm = &amd_gpio_pm_ops, ++#endif + }, + .probe = amd_gpio_probe, + .remove = amd_gpio_remove, +--- a/drivers/pinctrl/pinctrl-amd.h ++++ b/drivers/pinctrl/pinctrl-amd.h +@@ -95,6 +95,7 @@ struct amd_gpio { + struct gpio_chip gc; + struct resource *res; + struct platform_device *pdev; ++ u32 *saved_regs; + }; + + /* KERNCZ configuration*/ diff --git a/queue-4.4/series b/queue-4.4/series index 19ec0b448fa..6c3a880c109 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -14,3 +14,5 @@ x86-fsgsbase-64-report-fsbase-and-gsbase-correctly-in-core-dumps.patch md-raid5-release-flush-io-in-raid5_do_work.patch nfsd-fix-general-protection-fault-in-release_lock_stateid.patch mm-prevent-double-decrease-of-nr_reserved_highatomic.patch +tty-improve-tty_insert_flip_char-fast-path.patch +pinctrl-amd-save-pin-registers-over-suspend-resume.patch diff --git a/queue-4.4/tty-improve-tty_insert_flip_char-fast-path.patch b/queue-4.4/tty-improve-tty_insert_flip_char-fast-path.patch new file mode 100644 index 00000000000..edf6d338af5 --- /dev/null +++ b/queue-4.4/tty-improve-tty_insert_flip_char-fast-path.patch @@ -0,0 +1,94 @@ +From 979990c6284814617d8f2179d197f72ff62b5d85 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Tue, 20 Jun 2017 23:10:41 +0200 +Subject: tty: improve tty_insert_flip_char() fast path + +From: Arnd Bergmann + +commit 979990c6284814617d8f2179d197f72ff62b5d85 upstream. + +kernelci.org reports a crazy stack usage for the VT code when CONFIG_KASAN +is enabled: + +drivers/tty/vt/keyboard.c: In function 'kbd_keycode': +drivers/tty/vt/keyboard.c:1452:1: error: the frame size of 2240 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] + +The problem is that tty_insert_flip_char() gets inlined many times into +kbd_keycode(), and also into other functions, and each copy requires 128 +bytes for stack redzone to check for a possible out-of-bounds access on +the 'ch' and 'flags' arguments that are passed into +tty_insert_flip_string_flags as a variable-length string. + +This introduces a new __tty_insert_flip_char() function for the slow +path, which receives the two arguments by value. This completely avoids +the problem and the stack usage goes back down to around 100 bytes. + +Without KASAN, this is also slightly better, as we don't have to +spill the arguments to the stack but can simply pass 'ch' and 'flag' +in registers, saving a few bytes in .text for each call site. + +This should be backported to linux-4.0 or later, which first introduced +the stack sanitizer in the kernel. + +Fixes: c420f167db8c ("kasan: enable stack instrumentation") +Signed-off-by: Arnd Bergmann +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/tty/tty_buffer.c | 24 ++++++++++++++++++++++++ + include/linux/tty_flip.h | 3 ++- + 2 files changed, 26 insertions(+), 1 deletion(-) + +--- a/drivers/tty/tty_buffer.c ++++ b/drivers/tty/tty_buffer.c +@@ -362,6 +362,30 @@ int tty_insert_flip_string_flags(struct + EXPORT_SYMBOL(tty_insert_flip_string_flags); + + /** ++ * __tty_insert_flip_char - Add one character to the tty buffer ++ * @port: tty port ++ * @ch: character ++ * @flag: flag byte ++ * ++ * Queue a single byte to the tty buffering, with an optional flag. ++ * This is the slow path of tty_insert_flip_char. ++ */ ++int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) ++{ ++ struct tty_buffer *tb = port->buf.tail; ++ int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; ++ ++ if (!tty_buffer_request_room(port, 1)) ++ return 0; ++ ++ *flag_buf_ptr(tb, tb->used) = flag; ++ *char_buf_ptr(tb, tb->used++) = ch; ++ ++ return 1; ++} ++EXPORT_SYMBOL(__tty_insert_flip_char); ++ ++/** + * tty_schedule_flip - push characters to ldisc + * @port: tty port to push from + * +--- a/include/linux/tty_flip.h ++++ b/include/linux/tty_flip.h +@@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struc + unsigned char **chars, size_t size); + extern void tty_flip_buffer_push(struct tty_port *port); + void tty_schedule_flip(struct tty_port *port); ++int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag); + + static inline int tty_insert_flip_char(struct tty_port *port, + unsigned char ch, char flag) +@@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(s + *char_buf_ptr(tb, tb->used++) = ch; + return 1; + } +- return tty_insert_flip_string_flags(port, &ch, &flag, 1); ++ return __tty_insert_flip_char(port, ch, flag); + } + + static inline int tty_insert_flip_string(struct tty_port *port,