Update
This commit is contained in:
parent
bc4187c9ad
commit
5d28857d5a
@ -1,40 +0,0 @@
|
||||
From 7045054c96224ead00aae09246f475dfe6202def Mon Sep 17 00:00:00 2001
|
||||
From: Danct12 <danct12@disroot.org>
|
||||
Date: Tue, 19 Jan 2021 10:09:01 +0700
|
||||
Subject: [PATCH] arm64: dts: allwinner: pinephone: stop LEDs on suspend
|
||||
|
||||
Signed-off-by: Danct12 <danct12@disroot.org>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi | 3 ---
|
||||
1 file changed, 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
index 02d82980c..00ed866ae 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
@@ -218,14 +218,12 @@
|
||||
function = LED_FUNCTION_INDICATOR;
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
gpios = <&pio 3 20 GPIO_ACTIVE_HIGH>; /* PD20 */
|
||||
- retain-state-suspended;
|
||||
};
|
||||
|
||||
green {
|
||||
function = LED_FUNCTION_INDICATOR;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
gpios = <&pio 3 18 GPIO_ACTIVE_HIGH>; /* PD18 */
|
||||
- retain-state-suspended;
|
||||
};
|
||||
|
||||
red {
|
||||
@@ -233,7 +231,6 @@
|
||||
function = LED_FUNCTION_INDICATOR;
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
gpios = <&pio 3 19 GPIO_ACTIVE_HIGH>; /* PD19 */
|
||||
- retain-state-suspended;
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
2.30.0
|
||||
|
@ -1,746 +0,0 @@
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index a74227ad082e..b5633b56391e 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2705,6 +2705,14 @@ S: Supported
|
||||
F: drivers/net/bonding/
|
||||
F: include/uapi/linux/if_bonding.h
|
||||
|
||||
+BOOTSPLASH
|
||||
+M: Max Staudt <mstaudt@suse.de>
|
||||
+L: linux-fbdev@vger.kernel.org
|
||||
+S: Maintained
|
||||
+F: drivers/video/fbdev/core/bootsplash*.*
|
||||
+F: drivers/video/fbdev/core/dummycon.c
|
||||
+F: include/linux/bootsplash.h
|
||||
+
|
||||
BPF (Safe dynamic programs and tools)
|
||||
M: Alexei Starovoitov <ast@kernel.org>
|
||||
M: Daniel Borkmann <daniel@iogearbox.net>
|
||||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
|
||||
index 7f1f1fbcef9e..f3ff976266fe 100644
|
||||
--- a/drivers/video/console/Kconfig
|
||||
+++ b/drivers/video/console/Kconfig
|
||||
@@ -151,6 +151,30 @@ config FRAMEBUFFER_CONSOLE_ROTATION
|
||||
such that other users of the framebuffer will remain normally
|
||||
oriented.
|
||||
|
||||
+config BOOTSPLASH
|
||||
+ bool "Bootup splash screen"
|
||||
+ depends on FRAMEBUFFER_CONSOLE
|
||||
+ help
|
||||
+ This option enables the Linux bootsplash screen.
|
||||
+
|
||||
+ The bootsplash is a full-screen logo or animation indicating a
|
||||
+ booting system. It replaces the classic scrolling text with a
|
||||
+ graphical alternative, similar to other systems.
|
||||
+
|
||||
+ Since this is technically implemented as a hook on top of fbcon,
|
||||
+ it can only work if the FRAMEBUFFER_CONSOLE is enabled and a
|
||||
+ framebuffer driver is active. Thus, to get a text-free boot,
|
||||
+ the system needs to boot with vesafb, efifb, or similar.
|
||||
+
|
||||
+ Once built into the kernel, the bootsplash needs to be enabled
|
||||
+ with bootsplash.enabled=1 and a splash file needs to be supplied.
|
||||
+
|
||||
+ Further documentation can be found in:
|
||||
+ Documentation/fb/bootsplash.txt
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+ This is typically used by distributors and system integrators.
|
||||
+
|
||||
config STI_CONSOLE
|
||||
bool "STI text console"
|
||||
depends on PARISC
|
||||
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
|
||||
index 73493bbd7a15..66895321928e 100644
|
||||
--- a/drivers/video/fbdev/core/Makefile
|
||||
+++ b/drivers/video/fbdev/core/Makefile
|
||||
@@ -29,3 +29,6 @@ obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
|
||||
obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
|
||||
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
|
||||
obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
||||
+
|
||||
+obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
|
||||
+ dummyblit.o
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
new file mode 100644
|
||||
index 000000000000..e449755af268
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -0,0 +1,294 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Main file: Glue code, workers, timer, PM, kernel and userland API)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
||||
+
|
||||
+
|
||||
+#include <linux/atomic.h>
|
||||
+#include <linux/bootsplash.h>
|
||||
+#include <linux/console.h>
|
||||
+#include <linux/device.h> /* dev_warn() */
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/jiffies.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/printk.h>
|
||||
+#include <linux/selection.h> /* console_blanked */
|
||||
+#include <linux/stringify.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+#include <linux/vt_kern.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#include "bootsplash_internal.h"
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * We only have one splash screen, so let's keep a single
|
||||
+ * instance of the internal state.
|
||||
+ */
|
||||
+static struct splash_priv splash_state;
|
||||
+
|
||||
+
|
||||
+static void splash_callback_redraw_vc(struct work_struct *ignored)
|
||||
+{
|
||||
+ if (console_blanked)
|
||||
+ return;
|
||||
+
|
||||
+ console_lock();
|
||||
+ if (vc_cons[fg_console].d)
|
||||
+ update_screen(vc_cons[fg_console].d);
|
||||
+ console_unlock();
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static bool is_fb_compatible(const struct fb_info *info)
|
||||
+{
|
||||
+ if (!(info->flags & FBINFO_BE_MATH)
|
||||
+ != !fb_be_math((struct fb_info *)info)) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw on foreign endianness framebuffer.\n");
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->flags & FBINFO_MISC_TILEBLITTING) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw splash on tiling framebuffer.\n");
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->fix.type != FB_TYPE_PACKED_PIXELS
|
||||
+ || (info->fix.visual != FB_VISUAL_TRUECOLOR
|
||||
+ && info->fix.visual != FB_VISUAL_DIRECTCOLOR)) {
|
||||
+ dev_warn(info->device,
|
||||
+ "Can't draw splash on non-packed or non-truecolor framebuffer.\n");
|
||||
+
|
||||
+ dev_warn(info->device,
|
||||
+ " type: %u visual: %u\n",
|
||||
+ info->fix.type, info->fix.visual);
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (info->var.bits_per_pixel != 16
|
||||
+ && info->var.bits_per_pixel != 24
|
||||
+ && info->var.bits_per_pixel != 32) {
|
||||
+ dev_warn(info->device,
|
||||
+ "We only support drawing on framebuffers with 16, 24, or 32 bpp, not %d.\n",
|
||||
+ info->var.bits_per_pixel);
|
||||
+
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Called by fbcon_switch() when an instance is activated or refreshed.
|
||||
+ */
|
||||
+void bootsplash_render_full(struct fb_info *info)
|
||||
+{
|
||||
+ if (!is_fb_compatible(info))
|
||||
+ return;
|
||||
+
|
||||
+ bootsplash_do_render_background(info);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * External status enquiry and on/off switch
|
||||
+ */
|
||||
+bool bootsplash_would_render_now(void)
|
||||
+{
|
||||
+ return !oops_in_progress
|
||||
+ && !console_blanked
|
||||
+ && bootsplash_is_enabled();
|
||||
+}
|
||||
+
|
||||
+bool bootsplash_is_enabled(void)
|
||||
+{
|
||||
+ bool was_enabled;
|
||||
+
|
||||
+ /* Make sure we have the newest state */
|
||||
+ smp_rmb();
|
||||
+
|
||||
+ was_enabled = test_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ return was_enabled;
|
||||
+}
|
||||
+
|
||||
+void bootsplash_disable(void)
|
||||
+{
|
||||
+ int was_enabled;
|
||||
+
|
||||
+ was_enabled = test_and_clear_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ if (was_enabled) {
|
||||
+ if (oops_in_progress) {
|
||||
+ /* Redraw screen now so we can see a panic */
|
||||
+ if (vc_cons[fg_console].d)
|
||||
+ update_screen(vc_cons[fg_console].d);
|
||||
+ } else {
|
||||
+ /* No urgency, redraw at next opportunity */
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void bootsplash_enable(void)
|
||||
+{
|
||||
+ bool was_enabled;
|
||||
+
|
||||
+ if (oops_in_progress)
|
||||
+ return;
|
||||
+
|
||||
+ was_enabled = test_and_set_bit(0, &splash_state.enabled);
|
||||
+
|
||||
+ if (!was_enabled)
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Userland API via platform device in sysfs
|
||||
+ */
|
||||
+static ssize_t splash_show_enabled(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ return sprintf(buf, "%d\n", bootsplash_is_enabled());
|
||||
+}
|
||||
+
|
||||
+static ssize_t splash_store_enabled(struct device *device,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ bool enable;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!buf || !count)
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ err = kstrtobool(buf, &enable);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (enable)
|
||||
+ bootsplash_enable();
|
||||
+ else
|
||||
+ bootsplash_disable();
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
|
||||
+
|
||||
+
|
||||
+static struct attribute *splash_dev_attrs[] = {
|
||||
+ &dev_attr_enabled.attr,
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+ATTRIBUTE_GROUPS(splash_dev);
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Power management fixup via platform device
|
||||
+ *
|
||||
+ * When the system is woken from sleep or restored after hibernating, we
|
||||
+ * cannot expect the screen contents to still be present in video RAM.
|
||||
+ * Thus, we have to redraw the splash if we're currently active.
|
||||
+ */
|
||||
+static int splash_resume(struct device *device)
|
||||
+{
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int splash_suspend(struct device *device)
|
||||
+{
|
||||
+ cancel_work_sync(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static const struct dev_pm_ops splash_pm_ops = {
|
||||
+ .thaw = splash_resume,
|
||||
+ .restore = splash_resume,
|
||||
+ .resume = splash_resume,
|
||||
+ .suspend = splash_suspend,
|
||||
+ .freeze = splash_suspend,
|
||||
+};
|
||||
+
|
||||
+static struct platform_driver splash_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "bootsplash",
|
||||
+ .pm = &splash_pm_ops,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Main init
|
||||
+ */
|
||||
+void bootsplash_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Initialized already? */
|
||||
+ if (splash_state.splash_device)
|
||||
+ return;
|
||||
+
|
||||
+
|
||||
+ /* Register platform device to export user API */
|
||||
+ ret = platform_driver_register(&splash_driver);
|
||||
+ if (ret) {
|
||||
+ pr_err("platform_driver_register() failed: %d\n", ret);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ splash_state.splash_device
|
||||
+ = platform_device_alloc("bootsplash", 0);
|
||||
+
|
||||
+ if (!splash_state.splash_device)
|
||||
+ goto err_driver;
|
||||
+
|
||||
+ splash_state.splash_device->dev.groups = splash_dev_groups;
|
||||
+
|
||||
+ ret = platform_device_add(splash_state.splash_device);
|
||||
+ if (ret) {
|
||||
+ pr_err("platform_device_add() failed: %d\n", ret);
|
||||
+ goto err_device;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_device:
|
||||
+ platform_device_put(splash_state.splash_device);
|
||||
+ splash_state.splash_device = NULL;
|
||||
+err_driver:
|
||||
+ platform_driver_unregister(&splash_driver);
|
||||
+err:
|
||||
+ pr_err("Failed to initialize.\n");
|
||||
+}
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
new file mode 100644
|
||||
index 000000000000..b11da5cb90bf
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
@@ -0,0 +1,55 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Internal data structures used at runtime)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#ifndef __BOOTSPLASH_INTERNAL_H
|
||||
+#define __BOOTSPLASH_INTERNAL_H
|
||||
+
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Runtime types
|
||||
+ */
|
||||
+struct splash_priv {
|
||||
+ /*
|
||||
+ * Enabled/disabled state, to be used with atomic bit operations.
|
||||
+ * Bit 0: 0 = Splash hidden
|
||||
+ * 1 = Splash shown
|
||||
+ *
|
||||
+ * Note: fbcon.c uses this twice, by calling
|
||||
+ * bootsplash_would_render_now() in set_blitting_type() and
|
||||
+ * in fbcon_switch().
|
||||
+ * This is racy, but eventually consistent: Turning the
|
||||
+ * splash on/off will cause a redraw, which calls
|
||||
+ * fbcon_switch(), which calls set_blitting_type().
|
||||
+ * So the last on/off toggle will make things consistent.
|
||||
+ */
|
||||
+ unsigned long enabled;
|
||||
+
|
||||
+ /* Our gateway to userland via sysfs */
|
||||
+ struct platform_device *splash_device;
|
||||
+
|
||||
+ struct work_struct work_redraw_vc;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Rendering functions
|
||||
+ */
|
||||
+void bootsplash_do_render_background(struct fb_info *info);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
new file mode 100644
|
||||
index 000000000000..4d7e0117f653
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -0,0 +1,93 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Rendering functions)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
||||
+
|
||||
+
|
||||
+#include <linux/bootsplash.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/printk.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#include "bootsplash_internal.h"
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Rendering: Internal drawing routines
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Pack pixel into target format and do Big/Little Endian handling.
|
||||
+ * This would be a good place to handle endianness conversion if necessary.
|
||||
+ */
|
||||
+static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
|
||||
+ u8 red, u8 green, u8 blue)
|
||||
+{
|
||||
+ u32 dstpix;
|
||||
+
|
||||
+ /* Quantize pixel */
|
||||
+ red = red >> (8 - dst_var->red.length);
|
||||
+ green = green >> (8 - dst_var->green.length);
|
||||
+ blue = blue >> (8 - dst_var->blue.length);
|
||||
+
|
||||
+ /* Pack pixel */
|
||||
+ dstpix = red << (dst_var->red.offset)
|
||||
+ | green << (dst_var->green.offset)
|
||||
+ | blue << (dst_var->blue.offset);
|
||||
+
|
||||
+ /*
|
||||
+ * Move packed pixel to the beginning of the memory cell,
|
||||
+ * so we can memcpy() it out easily
|
||||
+ */
|
||||
+#ifdef __BIG_ENDIAN
|
||||
+ switch (dst_var->bits_per_pixel) {
|
||||
+ case 16:
|
||||
+ dstpix <<= 16;
|
||||
+ break;
|
||||
+ case 24:
|
||||
+ dstpix <<= 8;
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ break;
|
||||
+ }
|
||||
+#else
|
||||
+ /* This is intrinsically unnecessary on Little Endian */
|
||||
+#endif
|
||||
+
|
||||
+ return dstpix;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_render_background(struct fb_info *info)
|
||||
+{
|
||||
+ unsigned int x, y;
|
||||
+ u32 dstpix;
|
||||
+ u32 dst_octpp = info->var.bits_per_pixel / 8;
|
||||
+
|
||||
+ dstpix = pack_pixel(&info->var,
|
||||
+ 0,
|
||||
+ 0,
|
||||
+ 0);
|
||||
+
|
||||
+ for (y = 0; y < info->var.yres_virtual; y++) {
|
||||
+ u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
|
||||
+
|
||||
+ for (x = 0; x < info->var.xres_virtual; x++) {
|
||||
+ memcpy(dstline, &dstpix, dst_octpp);
|
||||
+
|
||||
+ dstline += dst_octpp;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/drivers/video/fbdev/core/dummyblit.c b/drivers/video/fbdev/core/dummyblit.c
|
||||
new file mode 100644
|
||||
index 000000000000..8c22ff92ce24
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/dummyblit.c
|
||||
@@ -0,0 +1,89 @@
|
||||
+/*
|
||||
+ * linux/drivers/video/fbdev/core/dummyblit.c -- Dummy Blitting Operation
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * These functions are used in place of blitblit/tileblit to suppress
|
||||
+ * fbcon's text output while a splash is shown.
|
||||
+ *
|
||||
+ * Only suppressing actual rendering keeps the text buffer in the VC layer
|
||||
+ * intact and makes it easy to switch back from the bootsplash to a full
|
||||
+ * text console with a simple redraw (with the original functions in place).
|
||||
+ *
|
||||
+ * Based on linux/drivers/video/fbdev/core/bitblit.c
|
||||
+ * and linux/drivers/video/fbdev/core/tileblit.c
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/vt_kern.h>
|
||||
+#include <linux/console.h>
|
||||
+#include <asm/types.h>
|
||||
+#include "fbcon.h"
|
||||
+
|
||||
+static void dummy_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
+ int sx, int dy, int dx, int height, int width)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
||||
+ int sx, int height, int width)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_putcs(struct vc_data *vc, struct fb_info *info,
|
||||
+ const unsigned short *s, int count, int yy, int xx,
|
||||
+ int fg, int bg)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_clear_margins(struct vc_data *vc, struct fb_info *info,
|
||||
+ int color, int bottom_only)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static void dummy_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
+{
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static int dummy_update_start(struct fb_info *info)
|
||||
+{
|
||||
+ /*
|
||||
+ * Copied from bitblit.c and tileblit.c
|
||||
+ *
|
||||
+ * As of Linux 4.12, nobody seems to care about our return value.
|
||||
+ */
|
||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ int err;
|
||||
+
|
||||
+ err = fb_pan_display(info, &ops->var);
|
||||
+ ops->var.xoffset = info->var.xoffset;
|
||||
+ ops->var.yoffset = info->var.yoffset;
|
||||
+ ops->var.vmode = info->var.vmode;
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+void fbcon_set_dummyops(struct fbcon_ops *ops)
|
||||
+{
|
||||
+ ops->bmove = dummy_bmove;
|
||||
+ ops->clear = dummy_clear;
|
||||
+ ops->putcs = dummy_putcs;
|
||||
+ ops->clear_margins = dummy_clear_margins;
|
||||
+ ops->cursor = dummy_cursor;
|
||||
+ ops->update_start = dummy_update_start;
|
||||
+ ops->rotate_font = NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(fbcon_set_dummyops);
|
||||
+
|
||||
+MODULE_AUTHOR("Max Staudt <mstaudt@suse.de>");
|
||||
+MODULE_DESCRIPTION("Dummy Blitting Operation");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
||||
index 04612f938bab..9a39a6fcfe98 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -80,6 +80,7 @@
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "fbcon.h"
|
||||
+#include <linux/bootsplash.h>
|
||||
|
||||
#ifdef FBCONDEBUG
|
||||
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
|
||||
@@ -542,6 +543,8 @@ static int do_fbcon_takeover(int show_logo)
|
||||
for (i = first_fb_vc; i <= last_fb_vc; i++)
|
||||
con2fb_map[i] = info_idx;
|
||||
|
||||
+ bootsplash_init();
|
||||
+
|
||||
err = do_take_over_console(&fb_con, first_fb_vc, last_fb_vc,
|
||||
fbcon_is_default);
|
||||
|
||||
@@ -661,6 +664,9 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
||||
else {
|
||||
fbcon_set_rotation(info);
|
||||
fbcon_set_bitops(ops);
|
||||
+
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ fbcon_set_dummyops(ops);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +689,19 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
|
||||
ops->p = &fb_display[vc->vc_num];
|
||||
fbcon_set_rotation(info);
|
||||
fbcon_set_bitops(ops);
|
||||
+
|
||||
+ /*
|
||||
+ * Note:
|
||||
+ * This is *eventually correct*.
|
||||
+ * Setting the fbcon operations and drawing the splash happen at
|
||||
+ * different points in time. If the splash is enabled/disabled
|
||||
+ * in between, then bootsplash_{en,dis}able will schedule a
|
||||
+ * redraw, which will again render the splash (or not) and set
|
||||
+ * the correct fbcon ops.
|
||||
+ * The last run will then be the right one.
|
||||
+ */
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ fbcon_set_dummyops(ops);
|
||||
}
|
||||
|
||||
static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
|
||||
@@ -2184,6 +2203,9 @@ static int fbcon_switch(struct vc_data *vc)
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
ops = info->fbcon_par;
|
||||
|
||||
+ if (bootsplash_would_render_now())
|
||||
+ bootsplash_render_full(info);
|
||||
+
|
||||
if (softback_top) {
|
||||
if (softback_lines)
|
||||
fbcon_set_origin(vc);
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
|
||||
index 18f3ac144237..45f94347fe5e 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.h
|
||||
+++ b/drivers/video/fbdev/core/fbcon.h
|
||||
@@ -214,6 +214,11 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
|
||||
#define SCROLL_REDRAW 0x004
|
||||
#define SCROLL_PAN_REDRAW 0x005
|
||||
|
||||
+#ifdef CONFIG_BOOTSPLASH
|
||||
+extern void fbcon_set_dummyops(struct fbcon_ops *ops);
|
||||
+#else /* CONFIG_BOOTSPLASH */
|
||||
+#define fbcon_set_dummyops(x)
|
||||
+#endif /* CONFIG_BOOTSPLASH */
|
||||
#ifdef CONFIG_FB_TILEBLITTING
|
||||
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
|
||||
#endif
|
||||
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
|
||||
new file mode 100644
|
||||
index 000000000000..c6dd0b43180d
|
||||
--- /dev/null
|
||||
+++ b/include/linux/bootsplash.h
|
||||
@@ -0,0 +1,43 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_BOOTSPLASH_H
|
||||
+#define __LINUX_BOOTSPLASH_H
|
||||
+
|
||||
+#include <linux/fb.h>
|
||||
+
|
||||
+
|
||||
+#ifdef CONFIG_BOOTSPLASH
|
||||
+
|
||||
+extern void bootsplash_render_full(struct fb_info *info);
|
||||
+
|
||||
+extern bool bootsplash_would_render_now(void);
|
||||
+
|
||||
+extern bool bootsplash_is_enabled(void);
|
||||
+extern void bootsplash_disable(void);
|
||||
+extern void bootsplash_enable(void);
|
||||
+
|
||||
+extern void bootsplash_init(void);
|
||||
+
|
||||
+#else /* CONFIG_BOOTSPLASH */
|
||||
+
|
||||
+#define bootsplash_render_full(x)
|
||||
+
|
||||
+#define bootsplash_would_render_now() (false)
|
||||
+
|
||||
+#define bootsplash_is_enabled() (false)
|
||||
+#define bootsplash_disable()
|
||||
+#define bootsplash_enable()
|
||||
+
|
||||
+#define bootsplash_init()
|
||||
+
|
||||
+#endif /* CONFIG_BOOTSPLASH */
|
||||
+
|
||||
+
|
||||
+#endif
|
@ -1,150 +0,0 @@
|
||||
--- b/drivers/video/fbdev/core/bitblit.c
|
||||
+++ a/drivers/video/fbdev/core/bitblit.c
|
||||
@@ -234,7 +234,7 @@
|
||||
}
|
||||
|
||||
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
- int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -247,6 +247,15 @@
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
|
||||
--- b/drivers/video/fbdev/core/fbcon.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -394,7 +394,7 @@
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
||||
CM_ERASE : CM_DRAW;
|
||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
}
|
||||
@@ -1345,7 +1345,7 @@
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
|
||||
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
}
|
||||
|
||||
--- b/drivers/video/fbdev/core/fbcon.h
|
||||
+++ a/drivers/video/fbdev/core/fbcon.h
|
||||
@@ -62,7 +62,7 @@
|
||||
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
|
||||
int color, int bottom_only);
|
||||
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg);
|
||||
- int fg, int bg);
|
||||
int (*update_start)(struct fb_info *info);
|
||||
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
|
||||
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
|
||||
--- b/drivers/video/fbdev/core/fbcon_ccw.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon_ccw.c
|
||||
@@ -219,7 +219,7 @@
|
||||
}
|
||||
|
||||
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
- int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -236,6 +236,15 @@
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
--- b/drivers/video/fbdev/core/fbcon_cw.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon_cw.c
|
||||
@@ -202,7 +202,7 @@
|
||||
}
|
||||
|
||||
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
- int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -219,6 +219,15 @@
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
||||
--- b/drivers/video/fbdev/core/fbcon_ud.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon_ud.c
|
||||
@@ -249,7 +249,7 @@
|
||||
}
|
||||
|
||||
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
- int fg, int bg)
|
||||
{
|
||||
struct fb_cursor cursor;
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
@@ -267,6 +267,15 @@
|
||||
|
||||
cursor.set = 0;
|
||||
|
||||
+ if (softback_lines) {
|
||||
+ if (y + softback_lines >= vc->vc_rows) {
|
||||
+ mode = CM_ERASE;
|
||||
+ ops->cursor_flash = 0;
|
||||
+ return;
|
||||
+ } else
|
||||
+ y += softback_lines;
|
||||
+ }
|
||||
+
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
attribute = get_attribute(info, c);
|
||||
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
|
||||
--- b/drivers/video/fbdev/core/tileblit.c
|
||||
+++ a/drivers/video/fbdev/core/tileblit.c
|
||||
@@ -80,7 +80,7 @@
|
||||
}
|
||||
|
||||
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
||||
+ int softback_lines, int fg, int bg)
|
||||
- int fg, int bg)
|
||||
{
|
||||
struct fb_tilecursor cursor;
|
||||
int use_sw = (vc->vc_cursor_type & 0x10);
|
@ -1,67 +0,0 @@
|
||||
From 27061f0b322a585c30db111719f89c23c15a88b4 Mon Sep 17 00:00:00 2001
|
||||
From: Sathish Narasimman <nsathish41@gmail.com>
|
||||
Date: Thu, 29 Oct 2020 13:18:21 +0530
|
||||
Subject: Bluetooth: Fix: LL PRivacy BLE device fails to connect
|
||||
|
||||
When adding device to white list the device is added to resolving list
|
||||
also. It has to be added only when HCI_ENABLE_LL_PRIVACY flag is set.
|
||||
HCI_ENABLE_LL_PRIVACY flag has to be tested before adding/deleting devices
|
||||
to resolving list. use_ll_privacy macro is used only to check if controller
|
||||
supports LL_Privacy.
|
||||
|
||||
https://bugzilla.kernel.org/show_bug.cgi?id=209745
|
||||
|
||||
Fixes: 0eee35bdfa3b ("Bluetooth: Update resolving list when updating whitelist")
|
||||
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
|
||||
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
|
||||
---
|
||||
net/bluetooth/hci_request.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
|
||||
index e0269192f2e5..a565c91b8599 100644
|
||||
--- a/net/bluetooth/hci_request.c
|
||||
+++ b/net/bluetooth/hci_request.c
|
||||
@@ -698,7 +698,8 @@ static void del_from_white_list(struct hci_request *req, bdaddr_t *bdaddr,
|
||||
cp.bdaddr_type);
|
||||
hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, sizeof(cp), &cp);
|
||||
|
||||
- if (use_ll_privacy(req->hdev)) {
|
||||
+ if (use_ll_privacy(req->hdev) &&
|
||||
+ hci_dev_test_flag(req->hdev, HCI_ENABLE_LL_PRIVACY)) {
|
||||
struct smp_irk *irk;
|
||||
|
||||
irk = hci_find_irk_by_addr(req->hdev, bdaddr, bdaddr_type);
|
||||
@@ -732,7 +733,8 @@ static int add_to_white_list(struct hci_request *req,
|
||||
return -1;
|
||||
|
||||
/* White list can not be used with RPAs */
|
||||
- if (!allow_rpa && !use_ll_privacy(hdev) &&
|
||||
+ if (!allow_rpa &&
|
||||
+ !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
|
||||
hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -750,7 +752,8 @@ static int add_to_white_list(struct hci_request *req,
|
||||
cp.bdaddr_type);
|
||||
hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp);
|
||||
|
||||
- if (use_ll_privacy(hdev)) {
|
||||
+ if (use_ll_privacy(hdev) &&
|
||||
+ hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY)) {
|
||||
struct smp_irk *irk;
|
||||
|
||||
irk = hci_find_irk_by_addr(hdev, ¶ms->addr,
|
||||
@@ -812,7 +815,8 @@ static u8 update_white_list(struct hci_request *req)
|
||||
}
|
||||
|
||||
/* White list can not be used with RPAs */
|
||||
- if (!allow_rpa && !use_ll_privacy(hdev) &&
|
||||
+ if (!allow_rpa &&
|
||||
+ !hci_dev_test_flag(hdev, HCI_ENABLE_LL_PRIVACY) &&
|
||||
hci_find_irk_by_addr(hdev, &b->bdaddr, b->bdaddr_type)) {
|
||||
return 0x00;
|
||||
}
|
||||
--
|
||||
cgit v1.2.3-1-gf6bb5
|
||||
|
@ -1,669 +0,0 @@
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index b5633b56391e..5c237445761e 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2712,6 +2712,7 @@ S: Maintained
|
||||
F: drivers/video/fbdev/core/bootsplash*.*
|
||||
F: drivers/video/fbdev/core/dummycon.c
|
||||
F: include/linux/bootsplash.h
|
||||
+F: include/uapi/linux/bootsplash_file.h
|
||||
|
||||
BPF (Safe dynamic programs and tools)
|
||||
M: Alexei Starovoitov <ast@kernel.org>
|
||||
diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile
|
||||
index 66895321928e..6a8d1bab8a01 100644
|
||||
--- a/drivers/video/fbdev/core/Makefile
|
||||
+++ b/drivers/video/fbdev/core/Makefile
|
||||
@@ -31,4 +31,4 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o
|
||||
obj-$(CONFIG_FB_DDC) += fb_ddc.o
|
||||
|
||||
obj-$(CONFIG_BOOTSPLASH) += bootsplash.o bootsplash_render.o \
|
||||
- dummyblit.o
|
||||
+ bootsplash_load.o dummyblit.o
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
index e449755af268..843c5400fefc 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "bootsplash_internal.h"
|
||||
+#include "uapi/linux/bootsplash_file.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -102,10 +103,17 @@ static bool is_fb_compatible(const struct fb_info *info)
|
||||
*/
|
||||
void bootsplash_render_full(struct fb_info *info)
|
||||
{
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+
|
||||
if (!is_fb_compatible(info))
|
||||
- return;
|
||||
+ goto out;
|
||||
+
|
||||
+ bootsplash_do_render_background(info, splash_state.file);
|
||||
+
|
||||
+ bootsplash_do_render_pictures(info, splash_state.file);
|
||||
|
||||
- bootsplash_do_render_background(info);
|
||||
+out:
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +124,7 @@ bool bootsplash_would_render_now(void)
|
||||
{
|
||||
return !oops_in_progress
|
||||
&& !console_blanked
|
||||
+ && splash_state.file
|
||||
&& bootsplash_is_enabled();
|
||||
}
|
||||
|
||||
@@ -252,6 +261,7 @@ static struct platform_driver splash_driver = {
|
||||
void bootsplash_init(void)
|
||||
{
|
||||
int ret;
|
||||
+ struct splash_file_priv *fp;
|
||||
|
||||
/* Initialized already? */
|
||||
if (splash_state.splash_device)
|
||||
@@ -280,8 +290,26 @@ void bootsplash_init(void)
|
||||
}
|
||||
|
||||
|
||||
+ mutex_init(&splash_state.data_lock);
|
||||
+ set_bit(0, &splash_state.enabled);
|
||||
+
|
||||
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
||||
|
||||
+
|
||||
+ if (!splash_state.bootfile || !strlen(splash_state.bootfile))
|
||||
+ return;
|
||||
+
|
||||
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
|
||||
+ splash_state.bootfile);
|
||||
+
|
||||
+ if (!fp)
|
||||
+ goto err;
|
||||
+
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+ splash_state.file = fp;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+
|
||||
return;
|
||||
|
||||
err_device:
|
||||
@@ -292,3 +320,7 @@ void bootsplash_init(void)
|
||||
err:
|
||||
pr_err("Failed to initialize.\n");
|
||||
}
|
||||
+
|
||||
+
|
||||
+module_param_named(bootfile, splash_state.bootfile, charp, 0444);
|
||||
+MODULE_PARM_DESC(bootfile, "Bootsplash file to load on boot");
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
index b11da5cb90bf..71e2a27ac0b8 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
@@ -15,15 +15,43 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fb.h>
|
||||
+#include <linux/firmware.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
+#include "uapi/linux/bootsplash_file.h"
|
||||
+
|
||||
|
||||
/*
|
||||
* Runtime types
|
||||
*/
|
||||
+struct splash_blob_priv {
|
||||
+ struct splash_blob_header *blob_header;
|
||||
+ const void *data;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+struct splash_pic_priv {
|
||||
+ const struct splash_pic_header *pic_header;
|
||||
+
|
||||
+ struct splash_blob_priv *blobs;
|
||||
+ u16 blobs_loaded;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+struct splash_file_priv {
|
||||
+ const struct firmware *fw;
|
||||
+ const struct splash_file_header *header;
|
||||
+
|
||||
+ struct splash_pic_priv *pics;
|
||||
+};
|
||||
+
|
||||
+
|
||||
struct splash_priv {
|
||||
+ /* Bootup and runtime state */
|
||||
+ char *bootfile;
|
||||
+
|
||||
/*
|
||||
* Enabled/disabled state, to be used with atomic bit operations.
|
||||
* Bit 0: 0 = Splash hidden
|
||||
@@ -43,6 +71,13 @@ struct splash_priv {
|
||||
struct platform_device *splash_device;
|
||||
|
||||
struct work_struct work_redraw_vc;
|
||||
+
|
||||
+ /* Splash data structures including lock for everything below */
|
||||
+ struct mutex data_lock;
|
||||
+
|
||||
+ struct fb_info *splash_fb;
|
||||
+
|
||||
+ struct splash_file_priv *file;
|
||||
};
|
||||
|
||||
|
||||
@@ -50,6 +85,14 @@ struct splash_priv {
|
||||
/*
|
||||
* Rendering functions
|
||||
*/
|
||||
-void bootsplash_do_render_background(struct fb_info *info);
|
||||
+void bootsplash_do_render_background(struct fb_info *info,
|
||||
+ const struct splash_file_priv *fp);
|
||||
+void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
+ const struct splash_file_priv *fp);
|
||||
+
|
||||
+
|
||||
+void bootsplash_free_file(struct splash_file_priv *fp);
|
||||
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
+ const char *path);
|
||||
|
||||
#endif
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
|
||||
new file mode 100644
|
||||
index 000000000000..fd807571ab7d
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_load.c
|
||||
@@ -0,0 +1,225 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Loading and freeing functions)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "bootsplash: " fmt
|
||||
+
|
||||
+
|
||||
+#include <linux/bootsplash.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/firmware.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/printk.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+
|
||||
+#include "bootsplash_internal.h"
|
||||
+#include "uapi/linux/bootsplash_file.h"
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Free all vmalloc()'d resources describing a splash file.
|
||||
+ */
|
||||
+void bootsplash_free_file(struct splash_file_priv *fp)
|
||||
+{
|
||||
+ if (!fp)
|
||||
+ return;
|
||||
+
|
||||
+ if (fp->pics) {
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+
|
||||
+ if (pp->blobs)
|
||||
+ vfree(pp->blobs);
|
||||
+ }
|
||||
+
|
||||
+ vfree(fp->pics);
|
||||
+ }
|
||||
+
|
||||
+ release_firmware(fp->fw);
|
||||
+ vfree(fp);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Load a splash screen from a "firmware" file.
|
||||
+ *
|
||||
+ * Parsing, and sanity checks.
|
||||
+ */
|
||||
+#ifdef __BIG_ENDIAN
|
||||
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_BE
|
||||
+#else
|
||||
+ #define BOOTSPLASH_MAGIC BOOTSPLASH_MAGIC_LE
|
||||
+#endif
|
||||
+
|
||||
+struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
+ const char *path)
|
||||
+{
|
||||
+ const struct firmware *fw;
|
||||
+ struct splash_file_priv *fp;
|
||||
+ unsigned int i;
|
||||
+ const u8 *walker;
|
||||
+
|
||||
+ if (request_firmware(&fw, path, device))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (fw->size < sizeof(struct splash_file_header)
|
||||
+ || memcmp(fw->data, BOOTSPLASH_MAGIC, sizeof(fp->header->id))) {
|
||||
+ pr_err("Not a bootsplash file.\n");
|
||||
+
|
||||
+ release_firmware(fw);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ fp = vzalloc(sizeof(struct splash_file_priv));
|
||||
+ if (!fp) {
|
||||
+ release_firmware(fw);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ pr_info("Loading splash file (%li bytes)\n", fw->size);
|
||||
+
|
||||
+ fp->fw = fw;
|
||||
+ fp->header = (struct splash_file_header *)fw->data;
|
||||
+
|
||||
+ /* Sanity checks */
|
||||
+ if (fp->header->version != BOOTSPLASH_VERSION) {
|
||||
+ pr_err("Loaded v%d file, but we only support version %d\n",
|
||||
+ fp->header->version,
|
||||
+ BOOTSPLASH_VERSION);
|
||||
+
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ if (fw->size < sizeof(struct splash_file_header)
|
||||
+ + fp->header->num_pics
|
||||
+ * sizeof(struct splash_pic_header)
|
||||
+ + fp->header->num_blobs
|
||||
+ * sizeof(struct splash_blob_header)) {
|
||||
+ pr_err("File incomplete.\n");
|
||||
+
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /* Read picture headers */
|
||||
+ if (fp->header->num_pics) {
|
||||
+ fp->pics = vzalloc(fp->header->num_pics
|
||||
+ * sizeof(struct splash_pic_priv));
|
||||
+ if (!fp->pics)
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ walker = fw->data + sizeof(struct splash_file_header);
|
||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+ struct splash_pic_header *ph = (void *)walker;
|
||||
+
|
||||
+ pr_debug("Picture %u: Size %ux%u\n", i, ph->width, ph->height);
|
||||
+
|
||||
+ if (ph->num_blobs < 1) {
|
||||
+ pr_err("Picture %u: Zero blobs? Aborting load.\n", i);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ pp->pic_header = ph;
|
||||
+ pp->blobs = vzalloc(ph->num_blobs
|
||||
+ * sizeof(struct splash_blob_priv));
|
||||
+ if (!pp->blobs)
|
||||
+ goto err;
|
||||
+
|
||||
+ walker += sizeof(struct splash_pic_header);
|
||||
+ }
|
||||
+
|
||||
+ /* Read blob headers */
|
||||
+ for (i = 0; i < fp->header->num_blobs; i++) {
|
||||
+ struct splash_blob_header *bh = (void *)walker;
|
||||
+ struct splash_pic_priv *pp;
|
||||
+
|
||||
+ if (walker + sizeof(struct splash_blob_header)
|
||||
+ > fw->data + fw->size)
|
||||
+ goto err;
|
||||
+
|
||||
+ walker += sizeof(struct splash_blob_header);
|
||||
+
|
||||
+ if (walker + bh->length > fw->data + fw->size)
|
||||
+ goto err;
|
||||
+
|
||||
+ if (bh->picture_id >= fp->header->num_pics)
|
||||
+ goto nextblob;
|
||||
+
|
||||
+ pp = &fp->pics[bh->picture_id];
|
||||
+
|
||||
+ pr_debug("Blob %u, pic %u, blobs_loaded %u, num_blobs %u.\n",
|
||||
+ i, bh->picture_id,
|
||||
+ pp->blobs_loaded, pp->pic_header->num_blobs);
|
||||
+
|
||||
+ if (pp->blobs_loaded >= pp->pic_header->num_blobs)
|
||||
+ goto nextblob;
|
||||
+
|
||||
+ switch (bh->type) {
|
||||
+ case 0:
|
||||
+ /* Raw 24-bit packed pixels */
|
||||
+ if (bh->length != pp->pic_header->width
|
||||
+ * pp->pic_header->height * 3) {
|
||||
+ pr_err("Blob %u, type 1: Length doesn't match picture.\n",
|
||||
+ i);
|
||||
+
|
||||
+ goto err;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ pr_warn("Blob %u, unknown type %u.\n", i, bh->type);
|
||||
+ goto nextblob;
|
||||
+ }
|
||||
+
|
||||
+ pp->blobs[pp->blobs_loaded].blob_header = bh;
|
||||
+ pp->blobs[pp->blobs_loaded].data = walker;
|
||||
+ pp->blobs_loaded++;
|
||||
+
|
||||
+nextblob:
|
||||
+ walker += bh->length;
|
||||
+ if (bh->length % 16)
|
||||
+ walker += 16 - (bh->length % 16);
|
||||
+ }
|
||||
+
|
||||
+ if (walker != fw->data + fw->size)
|
||||
+ pr_warn("Trailing data in splash file.\n");
|
||||
+
|
||||
+ /* Walk over pictures and ensure all blob slots are filled */
|
||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+
|
||||
+ if (pp->blobs_loaded != pp->pic_header->num_blobs) {
|
||||
+ pr_err("Picture %u doesn't have all blob slots filled.\n",
|
||||
+ i);
|
||||
+
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
|
||||
+ fw->size,
|
||||
+ fp->header->num_pics,
|
||||
+ fp->header->num_blobs);
|
||||
+
|
||||
+ return fp;
|
||||
+
|
||||
+
|
||||
+err:
|
||||
+ bootsplash_free_file(fp);
|
||||
+ return NULL;
|
||||
+}
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
index 4d7e0117f653..2ae36949d0e3 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "bootsplash_internal.h"
|
||||
+#include "uapi/linux/bootsplash_file.h"
|
||||
|
||||
|
||||
|
||||
@@ -70,16 +71,69 @@ static inline u32 pack_pixel(const struct fb_var_screeninfo *dst_var,
|
||||
}
|
||||
|
||||
|
||||
-void bootsplash_do_render_background(struct fb_info *info)
|
||||
+/*
|
||||
+ * Copy from source and blend into the destination picture.
|
||||
+ * Currently assumes that the source picture is 24bpp.
|
||||
+ * Currently assumes that the destination is <= 32bpp.
|
||||
+ */
|
||||
+static int splash_convert_to_fb(u8 *dst,
|
||||
+ const struct fb_var_screeninfo *dst_var,
|
||||
+ unsigned int dst_stride,
|
||||
+ unsigned int dst_xoff,
|
||||
+ unsigned int dst_yoff,
|
||||
+ const u8 *src,
|
||||
+ unsigned int src_width,
|
||||
+ unsigned int src_height)
|
||||
+{
|
||||
+ unsigned int x, y;
|
||||
+ unsigned int src_stride = 3 * src_width; /* Assume 24bpp packed */
|
||||
+ u32 dst_octpp = dst_var->bits_per_pixel / 8;
|
||||
+
|
||||
+ dst_xoff += dst_var->xoffset;
|
||||
+ dst_yoff += dst_var->yoffset;
|
||||
+
|
||||
+ /* Copy with stride and pixel size adjustment */
|
||||
+ for (y = 0;
|
||||
+ y < src_height && y + dst_yoff < dst_var->yres_virtual;
|
||||
+ y++) {
|
||||
+ const u8 *srcline = src + (y * src_stride);
|
||||
+ u8 *dstline = dst + ((y + dst_yoff) * dst_stride)
|
||||
+ + (dst_xoff * dst_octpp);
|
||||
+
|
||||
+ for (x = 0;
|
||||
+ x < src_width && x + dst_xoff < dst_var->xres_virtual;
|
||||
+ x++) {
|
||||
+ u8 red, green, blue;
|
||||
+ u32 dstpix;
|
||||
+
|
||||
+ /* Read pixel */
|
||||
+ red = *srcline++;
|
||||
+ green = *srcline++;
|
||||
+ blue = *srcline++;
|
||||
+
|
||||
+ /* Write pixel */
|
||||
+ dstpix = pack_pixel(dst_var, red, green, blue);
|
||||
+ memcpy(dstline, &dstpix, dst_octpp);
|
||||
+
|
||||
+ dstline += dst_octpp;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_render_background(struct fb_info *info,
|
||||
+ const struct splash_file_priv *fp)
|
||||
{
|
||||
unsigned int x, y;
|
||||
u32 dstpix;
|
||||
u32 dst_octpp = info->var.bits_per_pixel / 8;
|
||||
|
||||
dstpix = pack_pixel(&info->var,
|
||||
- 0,
|
||||
- 0,
|
||||
- 0);
|
||||
+ fp->header->bg_red,
|
||||
+ fp->header->bg_green,
|
||||
+ fp->header->bg_blue);
|
||||
|
||||
for (y = 0; y < info->var.yres_virtual; y++) {
|
||||
u8 *dstline = info->screen_buffer + (y * info->fix.line_length);
|
||||
@@ -91,3 +145,44 @@ void bootsplash_do_render_background(struct fb_info *info)
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
+ const struct splash_file_priv *fp)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
||||
+ struct splash_blob_priv *bp;
|
||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+ long dst_xoff, dst_yoff;
|
||||
+
|
||||
+ if (pp->blobs_loaded < 1)
|
||||
+ continue;
|
||||
+
|
||||
+ bp = &pp->blobs[0];
|
||||
+
|
||||
+ if (!bp || bp->blob_header->type != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
|
||||
+ dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
|
||||
+
|
||||
+ if (dst_xoff < 0
|
||||
+ || dst_yoff < 0
|
||||
+ || dst_xoff + pp->pic_header->width > info->var.xres
|
||||
+ || dst_yoff + pp->pic_header->height > info->var.yres) {
|
||||
+ pr_info_once("Picture %u is out of bounds at current resolution: %dx%d\n"
|
||||
+ "(this will only be printed once every reboot)\n",
|
||||
+ i, info->var.xres, info->var.yres);
|
||||
+
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Draw next splash frame */
|
||||
+ splash_convert_to_fb(info->screen_buffer, &info->var,
|
||||
+ info->fix.line_length, dst_xoff, dst_yoff,
|
||||
+ bp->data,
|
||||
+ pp->pic_header->width, pp->pic_header->height);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
||||
new file mode 100644
|
||||
index 000000000000..89dc9cca8f0c
|
||||
--- /dev/null
|
||||
+++ b/include/uapi/linux/bootsplash_file.h
|
||||
@@ -0,0 +1,118 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (File format)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
||||
+ */
|
||||
+
|
||||
+#ifndef __BOOTSPLASH_FILE_H
|
||||
+#define __BOOTSPLASH_FILE_H
|
||||
+
|
||||
+
|
||||
+#define BOOTSPLASH_VERSION 55561
|
||||
+
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * On-disk types
|
||||
+ *
|
||||
+ * A splash file consists of:
|
||||
+ * - One single 'struct splash_file_header'
|
||||
+ * - An array of 'struct splash_pic_header'
|
||||
+ * - An array of raw data blocks, each padded to 16 bytes and
|
||||
+ * preceded by a 'struct splash_blob_header'
|
||||
+ *
|
||||
+ * A single-frame splash may look like this:
|
||||
+ *
|
||||
+ * +--------------------+
|
||||
+ * | |
|
||||
+ * | splash_file_header |
|
||||
+ * | -> num_blobs = 1 |
|
||||
+ * | -> num_pics = 1 |
|
||||
+ * | |
|
||||
+ * +--------------------+
|
||||
+ * | |
|
||||
+ * | splash_pic_header |
|
||||
+ * | |
|
||||
+ * +--------------------+
|
||||
+ * | |
|
||||
+ * | splash_blob_header |
|
||||
+ * | -> type = 0 |
|
||||
+ * | -> picture_id = 0 |
|
||||
+ * | |
|
||||
+ * | (raw RGB data) |
|
||||
+ * | (pad to 16 bytes) |
|
||||
+ * | |
|
||||
+ * +--------------------+
|
||||
+ *
|
||||
+ * All multi-byte values are stored on disk in the native format
|
||||
+ * expected by the system the file will be used on.
|
||||
+ */
|
||||
+#define BOOTSPLASH_MAGIC_BE "Linux bootsplash"
|
||||
+#define BOOTSPLASH_MAGIC_LE "hsalpstoob xuniL"
|
||||
+
|
||||
+struct splash_file_header {
|
||||
+ uint8_t id[16]; /* "Linux bootsplash" (no trailing NUL) */
|
||||
+
|
||||
+ /* Splash file format version to avoid clashes */
|
||||
+ uint16_t version;
|
||||
+
|
||||
+ /* The background color */
|
||||
+ uint8_t bg_red;
|
||||
+ uint8_t bg_green;
|
||||
+ uint8_t bg_blue;
|
||||
+ uint8_t bg_reserved;
|
||||
+
|
||||
+ /*
|
||||
+ * Number of pic/blobs so we can allocate memory for internal
|
||||
+ * structures ahead of time when reading the file
|
||||
+ */
|
||||
+ uint16_t num_blobs;
|
||||
+ uint8_t num_pics;
|
||||
+
|
||||
+ uint8_t padding[103];
|
||||
+} __attribute__((__packed__));
|
||||
+
|
||||
+
|
||||
+struct splash_pic_header {
|
||||
+ uint16_t width;
|
||||
+ uint16_t height;
|
||||
+
|
||||
+ /*
|
||||
+ * Number of data packages associated with this picture.
|
||||
+ * Currently, the only use for more than 1 is for animations.
|
||||
+ */
|
||||
+ uint8_t num_blobs;
|
||||
+
|
||||
+ uint8_t padding[27];
|
||||
+} __attribute__((__packed__));
|
||||
+
|
||||
+
|
||||
+struct splash_blob_header {
|
||||
+ /* Length of the data block in bytes. */
|
||||
+ uint32_t length;
|
||||
+
|
||||
+ /*
|
||||
+ * Type of the contents.
|
||||
+ * 0 - Raw RGB data.
|
||||
+ */
|
||||
+ uint16_t type;
|
||||
+
|
||||
+ /*
|
||||
+ * Picture this blob is associated with.
|
||||
+ * Blobs will be added to a picture in the order they are
|
||||
+ * found in the file.
|
||||
+ */
|
||||
+ uint8_t picture_id;
|
||||
+
|
||||
+ uint8_t padding[9];
|
||||
+} __attribute__((__packed__));
|
||||
+
|
||||
+#endif
|
@ -1,31 +0,0 @@
|
||||
--- b/drivers/video/fbdev/core/fbcon.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -163,6 +163,8 @@
|
||||
|
||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
||||
|
||||
+static int fbcon_set_origin(struct vc_data *);
|
||||
+
|
||||
static int fbcon_cursor_noblink;
|
||||
|
||||
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
|
||||
@@ -2633,6 +2635,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
+static int fbcon_set_origin(struct vc_data *vc)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
void fbcon_suspended(struct fb_info *info)
|
||||
{
|
||||
struct vc_data *vc = NULL;
|
||||
@@ -3103,6 +3110,7 @@
|
||||
.con_font_default = fbcon_set_def_font,
|
||||
.con_font_copy = fbcon_copy_font,
|
||||
.con_set_palette = fbcon_set_palette,
|
||||
+ .con_set_origin = fbcon_set_origin,
|
||||
.con_invert_region = fbcon_invert_region,
|
||||
.con_screen_pos = fbcon_screen_pos,
|
||||
.con_getxy = fbcon_getxy,
|
@ -1,497 +0,0 @@
|
||||
--- b/drivers/video/fbdev/core/fbcon.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -122,6 +122,12 @@
|
||||
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
|
||||
enums. */
|
||||
static int logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+/* Software scrollback */
|
||||
+static int fbcon_softback_size = 32768;
|
||||
+static unsigned long softback_buf, softback_curr;
|
||||
+static unsigned long softback_in;
|
||||
+static unsigned long softback_top, softback_end;
|
||||
+static int softback_lines;
|
||||
/* console mappings */
|
||||
static int first_fb_vc;
|
||||
static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
||||
@@ -161,6 +167,8 @@
|
||||
|
||||
static const struct consw fb_con;
|
||||
|
||||
+#define CM_SOFTBACK (8)
|
||||
+
|
||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *);
|
||||
@@ -365,6 +373,18 @@
|
||||
return color;
|
||||
}
|
||||
|
||||
+static void fbcon_update_softback(struct vc_data *vc)
|
||||
+{
|
||||
+ int l = fbcon_softback_size / vc->vc_size_row;
|
||||
+
|
||||
+ if (l > 5)
|
||||
+ softback_end = softback_buf + l * vc->vc_size_row;
|
||||
+ else
|
||||
+ /* Smaller scrollback makes no sense, and 0 would screw
|
||||
+ the operation totally */
|
||||
+ softback_top = 0;
|
||||
+}
|
||||
+
|
||||
static void fb_flashcursor(struct work_struct *work)
|
||||
{
|
||||
struct fb_info *info = container_of(work, struct fb_info, queue);
|
||||
@@ -394,7 +414,7 @@
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
||||
CM_ERASE : CM_DRAW;
|
||||
+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
}
|
||||
@@ -451,7 +471,13 @@
|
||||
}
|
||||
|
||||
if (!strncmp(options, "scrollback:", 11)) {
|
||||
+ options += 11;
|
||||
+ if (*options) {
|
||||
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
|
||||
+ if (*options == 'k' || *options == 'K') {
|
||||
+ fbcon_softback_size *= 1024;
|
||||
+ }
|
||||
+ }
|
||||
- pr_warn("Ignoring scrollback size option\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -996,6 +1022,31 @@
|
||||
|
||||
set_blitting_type(vc, info);
|
||||
|
||||
+ if (info->fix.type != FB_TYPE_TEXT) {
|
||||
+ if (fbcon_softback_size) {
|
||||
+ if (!softback_buf) {
|
||||
+ softback_buf =
|
||||
+ (unsigned long)
|
||||
+ kvmalloc(fbcon_softback_size,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!softback_buf) {
|
||||
+ fbcon_softback_size = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_buf) {
|
||||
+ kvfree((void *) softback_buf);
|
||||
+ softback_buf = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (softback_buf)
|
||||
+ softback_in = softback_top = softback_curr =
|
||||
+ softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+
|
||||
/* Setup default font */
|
||||
if (!p->fontdata && !vc->vc_font.data) {
|
||||
if (!fontname[0] || !(font = find_font(fontname)))
|
||||
@@ -1169,6 +1220,9 @@
|
||||
if (logo)
|
||||
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
|
||||
|
||||
+ if (vc == svc && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
+
|
||||
if (ops->rotate_font && ops->rotate_font(info, vc)) {
|
||||
ops->rotate = FB_ROTATE_UR;
|
||||
set_blitting_type(vc, info);
|
||||
@@ -1331,6 +1385,7 @@
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ int y;
|
||||
int c = scr_readw((u16 *) vc->vc_pos);
|
||||
|
||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
||||
@@ -1344,8 +1399,16 @@
|
||||
fbcon_add_cursor_timer(info);
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
+ if (mode & CM_SOFTBACK) {
|
||||
+ mode &= ~CM_SOFTBACK;
|
||||
+ y = softback_lines;
|
||||
+ } else {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ y = 0;
|
||||
+ }
|
||||
|
||||
+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
}
|
||||
|
||||
@@ -1416,6 +1479,8 @@
|
||||
|
||||
if (con_is_visible(vc)) {
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +1618,99 @@
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
|
||||
+ long delta)
|
||||
+{
|
||||
+ int count = vc->vc_rows;
|
||||
+ unsigned short *d, *s;
|
||||
+ unsigned long n;
|
||||
+ int line = 0;
|
||||
+
|
||||
+ d = (u16 *) softback_curr;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ n = softback_curr + delta * vc->vc_size_row;
|
||||
+ softback_lines -= delta;
|
||||
+ if (delta < 0) {
|
||||
+ if (softback_curr < softback_top && n < softback_buf) {
|
||||
+ n += softback_end - softback_buf;
|
||||
+ if (n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else if (softback_curr >= softback_top
|
||||
+ && n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_curr > softback_in && n >= softback_end) {
|
||||
+ n += softback_buf - softback_end;
|
||||
+ if (n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ } else if (softback_curr <= softback_in && n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (n == softback_curr)
|
||||
+ return;
|
||||
+ softback_curr = n;
|
||||
+ s = (u16 *) softback_curr;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ while (count--) {
|
||||
+ unsigned short *start;
|
||||
+ unsigned short *le;
|
||||
+ unsigned short c;
|
||||
+ int x = 0;
|
||||
+ unsigned short attr = 1;
|
||||
+
|
||||
+ start = s;
|
||||
+ le = advance_row(s, 1);
|
||||
+ do {
|
||||
+ c = scr_readw(s);
|
||||
+ if (attr != (c & 0xff00)) {
|
||||
+ attr = c & 0xff00;
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start;
|
||||
+ start = s;
|
||||
+ }
|
||||
+ }
|
||||
+ if (c == scr_readw(d)) {
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start + 1;
|
||||
+ start = s + 1;
|
||||
+ } else {
|
||||
+ x++;
|
||||
+ start++;
|
||||
+ }
|
||||
+ }
|
||||
+ s++;
|
||||
+ d++;
|
||||
+ } while (s < le);
|
||||
+ if (s > start)
|
||||
+ fbcon_putcs(vc, start, s - start, line, x);
|
||||
+ line++;
|
||||
+ if (d == (u16 *) softback_end)
|
||||
+ d = (u16 *) softback_buf;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ if (s == (u16 *) softback_end)
|
||||
+ s = (u16 *) softback_buf;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy)
|
||||
{
|
||||
@@ -1692,6 +1850,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
|
||||
+ int count)
|
||||
+{
|
||||
+ unsigned short *p;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
|
||||
+
|
||||
+ while (count) {
|
||||
+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
|
||||
+ count--;
|
||||
+ p = advance_row(p, 1);
|
||||
+ softback_in += vc->vc_size_row;
|
||||
+ if (softback_in == softback_end)
|
||||
+ softback_in = softback_buf;
|
||||
+ if (softback_in == softback_top) {
|
||||
+ softback_top += vc->vc_size_row;
|
||||
+ if (softback_top == softback_end)
|
||||
+ softback_top = softback_buf;
|
||||
+ }
|
||||
+ }
|
||||
+ softback_curr = softback_in;
|
||||
+}
|
||||
+
|
||||
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int count)
|
||||
{
|
||||
@@ -1714,6 +1897,8 @@
|
||||
case SM_UP:
|
||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
||||
count = vc->vc_rows;
|
||||
+ if (softback_top)
|
||||
+ fbcon_softback_note(vc, t, count);
|
||||
if (logo_shown >= 0)
|
||||
goto redraw_up;
|
||||
switch (p->scrollmode) {
|
||||
@@ -2084,6 +2269,14 @@
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
ops = info->fbcon_par;
|
||||
|
||||
+ if (softback_top) {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ softback_top = softback_curr = softback_in = softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ fbcon_update_softback(vc);
|
||||
+ }
|
||||
+
|
||||
if (logo_shown >= 0) {
|
||||
struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
|
||||
@@ -2407,6 +2600,9 @@
|
||||
int cnt;
|
||||
char *old_data = NULL;
|
||||
|
||||
+ if (con_is_visible(vc) && softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+
|
||||
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
|
||||
if (p->userfont)
|
||||
old_data = vc->vc_font.data;
|
||||
@@ -2432,6 +2628,8 @@
|
||||
cols /= w;
|
||||
rows /= h;
|
||||
vc_resize(vc, cols, rows);
|
||||
+ if (con_is_visible(vc) && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
} else if (con_is_visible(vc)
|
||||
&& vc->vc_mode == KD_TEXT) {
|
||||
fbcon_clear_margins(vc, 0);
|
||||
@@ -2590,7 +2788,19 @@
|
||||
|
||||
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
|
||||
{
|
||||
+ unsigned long p;
|
||||
+ int line;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console || !softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset);
|
||||
+ line = offset / vc->vc_size_row;
|
||||
+ if (line >= softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset -
|
||||
+ softback_lines * vc->vc_size_row);
|
||||
+ p = softback_curr + offset;
|
||||
+ if (p >= softback_end)
|
||||
+ p += softback_buf - softback_end;
|
||||
+ return (u16 *) p;
|
||||
- return (u16 *) (vc->vc_origin + offset);
|
||||
}
|
||||
|
||||
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
|
||||
@@ -2604,7 +2814,22 @@
|
||||
|
||||
x = offset % vc->vc_cols;
|
||||
y = offset / vc->vc_cols;
|
||||
+ if (vc->vc_num == fg_console)
|
||||
+ y += softback_lines;
|
||||
ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ } else if (vc->vc_num == fg_console && softback_lines) {
|
||||
+ unsigned long offset = pos - softback_curr;
|
||||
+
|
||||
+ if (pos < softback_curr)
|
||||
+ offset += softback_end - softback_buf;
|
||||
+ offset /= 2;
|
||||
+ x = offset % vc->vc_cols;
|
||||
+ y = offset / vc->vc_cols;
|
||||
+ ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ if (ret == softback_end)
|
||||
+ ret = softback_buf;
|
||||
+ if (ret == softback_in)
|
||||
+ ret = vc->vc_origin;
|
||||
} else {
|
||||
/* Should not happen */
|
||||
x = y = 0;
|
||||
@@ -2632,11 +2857,106 @@
|
||||
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
|
||||
(((a) & 0x0700) << 4);
|
||||
scr_writew(a, p++);
|
||||
+ if (p == (u16 *) softback_end)
|
||||
+ p = (u16 *) softback_buf;
|
||||
+ if (p == (u16 *) softback_in)
|
||||
+ p = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void fbcon_scrolldelta(struct vc_data *vc, int lines)
|
||||
+{
|
||||
+ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
|
||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ struct fbcon_display *disp = &fb_display[fg_console];
|
||||
+ int offset, limit, scrollback_old;
|
||||
+
|
||||
+ if (softback_top) {
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ if (vc->vc_mode != KD_TEXT || !lines)
|
||||
+ return;
|
||||
+ if (logo_shown >= 0) {
|
||||
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
+
|
||||
+ if (conp2->vc_top == logo_lines
|
||||
+ && conp2->vc_bottom == conp2->vc_rows)
|
||||
+ conp2->vc_top = 0;
|
||||
+ if (logo_shown == vc->vc_num) {
|
||||
+ unsigned long p, q;
|
||||
+ int i;
|
||||
+
|
||||
+ p = softback_in;
|
||||
+ q = vc->vc_origin +
|
||||
+ logo_lines * vc->vc_size_row;
|
||||
+ for (i = 0; i < logo_lines; i++) {
|
||||
+ if (p == softback_top)
|
||||
+ break;
|
||||
+ if (p == softback_buf)
|
||||
+ p = softback_end;
|
||||
+ p -= vc->vc_size_row;
|
||||
+ q -= vc->vc_size_row;
|
||||
+ scr_memcpyw((u16 *) q, (u16 *) p,
|
||||
+ vc->vc_size_row);
|
||||
+ }
|
||||
+ softback_in = softback_curr = p;
|
||||
+ update_region(vc, vc->vc_origin,
|
||||
+ logo_lines * vc->vc_cols);
|
||||
+ }
|
||||
+ logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+ }
|
||||
+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
|
||||
+ fbcon_redraw_softback(vc, disp, lines);
|
||||
+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ if (!scrollback_phys_max)
|
||||
+ return;
|
||||
+
|
||||
+ scrollback_old = scrollback_current;
|
||||
+ scrollback_current -= lines;
|
||||
+ if (scrollback_current < 0)
|
||||
+ scrollback_current = 0;
|
||||
+ else if (scrollback_current > scrollback_max)
|
||||
+ scrollback_current = scrollback_max;
|
||||
+ if (scrollback_current == scrollback_old)
|
||||
+ return;
|
||||
+
|
||||
+ if (fbcon_is_inactive(vc, info))
|
||||
+ return;
|
||||
+
|
||||
+ fbcon_cursor(vc, CM_ERASE);
|
||||
+
|
||||
+ offset = disp->yscroll - scrollback_current;
|
||||
+ limit = disp->vrows;
|
||||
+ switch (disp->scrollmode) {
|
||||
+ case SCROLL_WRAP_MOVE:
|
||||
+ info->var.vmode |= FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ case SCROLL_PAN_MOVE:
|
||||
+ case SCROLL_PAN_REDRAW:
|
||||
+ limit -= vc->vc_rows;
|
||||
+ info->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (offset < 0)
|
||||
+ offset += limit;
|
||||
+ else if (offset >= limit)
|
||||
+ offset -= limit;
|
||||
+
|
||||
+ ops->var.xoffset = 0;
|
||||
+ ops->var.yoffset = offset * vc->vc_font.height;
|
||||
+ ops->update_start(info);
|
||||
+
|
||||
+ if (!scrollback_current)
|
||||
+ fbcon_cursor(vc, CM_DRAW);
|
||||
}
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *vc)
|
||||
{
|
||||
+ if (softback_lines)
|
||||
+ fbcon_scrolldelta(vc, softback_lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2700,6 +3020,8 @@
|
||||
|
||||
fbcon_set_palette(vc, color_table);
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3110,6 +3432,7 @@
|
||||
.con_font_default = fbcon_set_def_font,
|
||||
.con_font_copy = fbcon_copy_font,
|
||||
.con_set_palette = fbcon_set_palette,
|
||||
+ .con_scrolldelta = fbcon_scrolldelta,
|
||||
.con_set_origin = fbcon_set_origin,
|
||||
.con_invert_region = fbcon_invert_region,
|
||||
.con_screen_pos = fbcon_screen_pos,
|
||||
@@ -3344,6 +3667,9 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
+ kvfree((void *)softback_buf);
|
||||
+ softback_buf = 0UL;
|
||||
+
|
||||
for_each_registered_fb(i) {
|
||||
int pending = 0;
|
||||
|
@ -1,48 +0,0 @@
|
||||
From 4264c74c96e7907b60ee6ed82670317d19ed7ebe Mon Sep 17 00:00:00 2001
|
||||
From: Edward Vear <edwardvear@gmail.com>
|
||||
Date: Tue, 27 Oct 2020 00:02:03 -0700
|
||||
Subject: Bluetooth: Fix attempting to set RPA timeout when unsupported
|
||||
|
||||
During controller initialization, an LE Set RPA Timeout command is sent
|
||||
to the controller if supported. However, the value checked to determine
|
||||
if the command is supported is incorrect. Page 1921 of the Bluetooth
|
||||
Core Spec v5.2 shows that bit 2 of octet 35 of the Supported_Commands
|
||||
field corresponds to the LE Set RPA Timeout command, but currently
|
||||
bit 6 of octet 35 is checked. This patch checks the correct value
|
||||
instead.
|
||||
|
||||
This issue led to the error seen in the following btmon output during
|
||||
initialization of an adapter (rtl8761b) and prevented initialization
|
||||
from completing.
|
||||
|
||||
< HCI Command: LE Set Resolvable Private Address Timeout (0x08|0x002e) plen 2
|
||||
Timeout: 900 seconds
|
||||
> HCI Event: Command Complete (0x0e) plen 4
|
||||
LE Set Resolvable Private Address Timeout (0x08|0x002e) ncmd 2
|
||||
Status: Unsupported Remote Feature / Unsupported LMP Feature (0x1a)
|
||||
= Close Index: 00:E0:4C:6B:E5:03
|
||||
|
||||
The error did not appear when running with this patch.
|
||||
|
||||
Signed-off-by: Edward Vear <edwardvear@gmail.com>
|
||||
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
|
||||
---
|
||||
net/bluetooth/hci_core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
|
||||
index be9cdf5dabe5..30a5267af490 100644
|
||||
--- a/net/bluetooth/hci_core.c
|
||||
+++ b/net/bluetooth/hci_core.c
|
||||
@@ -763,7 +763,7 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
|
||||
hci_req_add(req, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL);
|
||||
}
|
||||
|
||||
- if (hdev->commands[35] & 0x40) {
|
||||
+ if (hdev->commands[35] & 0x04) {
|
||||
__le16 rpa_timeout = cpu_to_le16(hdev->rpa_timeout);
|
||||
|
||||
/* Set RPA timeout */
|
||||
--
|
||||
cgit v1.2.3-1-gf6bb5
|
||||
|
@ -1,40 +0,0 @@
|
||||
Bluetooth: btusb: Some Qualcomm Bluetooth adapters stop working
|
||||
This issue starts from linux-5.10-rc1, I reproduced this issue on my
|
||||
Dell Inspiron 7447 with BT adapter 0cf3:e005, the kernel will print
|
||||
out: "Bluetooth: hci0: don't support firmware rome 0x31010000", and
|
||||
someone else also reported the similar issue to bugzilla #211571.
|
||||
|
||||
I found this is a regression introduced by 'commit b40f58b97386
|
||||
("Bluetooth: btusb: Add Qualcomm Bluetooth SoC WCN6855 support"), the
|
||||
patch assumed that if high ROM version is not zero, it is an adapter
|
||||
on WCN6855, but many old adapters don't need to load rampatch or nvm,
|
||||
and they have non-zero high ROM version.
|
||||
|
||||
To fix it, let the driver match the rom_version in the
|
||||
qca_devices_table first, if there is no entry matched, check the
|
||||
high ROM version, if it is not zero, we assume this adapter is ready
|
||||
to work and no need to load rampatch and nvm like previously.
|
||||
|
||||
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=211571
|
||||
Fixes: b40f58b97386 ("Bluetooth: btusb: Add Qualcomm Bluetooth SoC WCN6855 support")
|
||||
Signed-off-by: Hui Wang <hui.wang@canonical.com>
|
||||
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
|
||||
|
||||
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
|
||||
index 03b83aa91277..32161dd40ed6 100644
|
||||
--- a/drivers/bluetooth/btusb.c
|
||||
+++ b/drivers/bluetooth/btusb.c
|
||||
@@ -4069,6 +4069,13 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
info = &qca_devices_table[i];
|
||||
}
|
||||
if (!info) {
|
||||
+ /* If the rom_version is not matched in the qca_devices_table
|
||||
+ * and the high ROM version is not zero, we assume this chip no
|
||||
+ * need to load the rampatch and nvm.
|
||||
+ */
|
||||
+ if (ver_rom & ~0xffffU)
|
||||
+ return 0;
|
||||
+
|
||||
bt_dev_err(hdev, "don't support firmware rome 0x%x", ver_rom);
|
||||
return -ENODEV;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
index 843c5400fefc..815b007f81ca 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -112,6 +112,8 @@ void bootsplash_render_full(struct fb_info *info)
|
||||
|
||||
bootsplash_do_render_pictures(info, splash_state.file);
|
||||
|
||||
+ bootsplash_do_render_flush(info);
|
||||
+
|
||||
out:
|
||||
mutex_unlock(&splash_state.data_lock);
|
||||
}
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
index 71e2a27ac0b8..0acb383aa4e3 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
@@ -89,6 +89,7 @@ void bootsplash_do_render_background(struct fb_info *info,
|
||||
const struct splash_file_priv *fp);
|
||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
const struct splash_file_priv *fp);
|
||||
+void bootsplash_do_render_flush(struct fb_info *info);
|
||||
|
||||
|
||||
void bootsplash_free_file(struct splash_file_priv *fp);
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
index 2ae36949d0e3..8c09c306ff67 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -186,3 +186,36 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
pp->pic_header->width, pp->pic_header->height);
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_render_flush(struct fb_info *info)
|
||||
+{
|
||||
+ /*
|
||||
+ * FB drivers using deferred_io (such as Xen) need to sync the
|
||||
+ * screen after modifying its contents. When the FB is mmap()ed
|
||||
+ * from userspace, this happens via a dirty pages callback, but
|
||||
+ * when modifying the FB from the kernel, there is no such thing.
|
||||
+ *
|
||||
+ * So let's issue a fake fb_copyarea (copying the FB onto itself)
|
||||
+ * to trick the FB driver into syncing the screen.
|
||||
+ *
|
||||
+ * A few DRM drivers' FB implementations are broken by not using
|
||||
+ * deferred_io when they really should - we match on the known
|
||||
+ * bad ones manually for now.
|
||||
+ */
|
||||
+ if (info->fbdefio
|
||||
+ || !strcmp(info->fix.id, "astdrmfb")
|
||||
+ || !strcmp(info->fix.id, "cirrusdrmfb")
|
||||
+ || !strcmp(info->fix.id, "mgadrmfb")) {
|
||||
+ struct fb_copyarea area;
|
||||
+
|
||||
+ area.dx = 0;
|
||||
+ area.dy = 0;
|
||||
+ area.width = info->var.xres;
|
||||
+ area.height = info->var.yres;
|
||||
+ area.sx = 0;
|
||||
+ area.sy = 0;
|
||||
+
|
||||
+ info->fbops->fb_copyarea(info, &area);
|
||||
+ }
|
||||
+}
|
@ -1,497 +0,0 @@
|
||||
--- b/drivers/video/fbdev/core/fbcon.c
|
||||
+++ a/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -122,6 +122,12 @@
|
||||
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
|
||||
enums. */
|
||||
static int logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+/* Software scrollback */
|
||||
+static int fbcon_softback_size = 32768;
|
||||
+static unsigned long softback_buf, softback_curr;
|
||||
+static unsigned long softback_in;
|
||||
+static unsigned long softback_top, softback_end;
|
||||
+static int softback_lines;
|
||||
/* console mappings */
|
||||
static int first_fb_vc;
|
||||
static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
||||
@@ -161,6 +167,8 @@
|
||||
|
||||
static const struct consw fb_con;
|
||||
|
||||
+#define CM_SOFTBACK (8)
|
||||
+
|
||||
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *);
|
||||
@@ -365,6 +373,18 @@
|
||||
return color;
|
||||
}
|
||||
|
||||
+static void fbcon_update_softback(struct vc_data *vc)
|
||||
+{
|
||||
+ int l = fbcon_softback_size / vc->vc_size_row;
|
||||
+
|
||||
+ if (l > 5)
|
||||
+ softback_end = softback_buf + l * vc->vc_size_row;
|
||||
+ else
|
||||
+ /* Smaller scrollback makes no sense, and 0 would screw
|
||||
+ the operation totally */
|
||||
+ softback_top = 0;
|
||||
+}
|
||||
+
|
||||
static void fb_flashcursor(struct work_struct *work)
|
||||
{
|
||||
struct fb_info *info = container_of(work, struct fb_info, queue);
|
||||
@@ -394,7 +414,7 @@
|
||||
c = scr_readw((u16 *) vc->vc_pos);
|
||||
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
|
||||
CM_ERASE : CM_DRAW;
|
||||
+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
console_unlock();
|
||||
}
|
||||
@@ -451,7 +471,13 @@
|
||||
}
|
||||
|
||||
if (!strncmp(options, "scrollback:", 11)) {
|
||||
+ options += 11;
|
||||
+ if (*options) {
|
||||
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
|
||||
+ if (*options == 'k' || *options == 'K') {
|
||||
+ fbcon_softback_size *= 1024;
|
||||
+ }
|
||||
+ }
|
||||
- pr_warn("Ignoring scrollback size option\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -996,6 +1022,31 @@
|
||||
|
||||
set_blitting_type(vc, info);
|
||||
|
||||
+ if (info->fix.type != FB_TYPE_TEXT) {
|
||||
+ if (fbcon_softback_size) {
|
||||
+ if (!softback_buf) {
|
||||
+ softback_buf =
|
||||
+ (unsigned long)
|
||||
+ kvmalloc(fbcon_softback_size,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!softback_buf) {
|
||||
+ fbcon_softback_size = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_buf) {
|
||||
+ kvfree((void *) softback_buf);
|
||||
+ softback_buf = 0;
|
||||
+ softback_top = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (softback_buf)
|
||||
+ softback_in = softback_top = softback_curr =
|
||||
+ softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+
|
||||
/* Setup default font */
|
||||
if (!p->fontdata && !vc->vc_font.data) {
|
||||
if (!fontname[0] || !(font = find_font(fontname)))
|
||||
@@ -1169,6 +1220,9 @@
|
||||
if (logo)
|
||||
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
|
||||
|
||||
+ if (vc == svc && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
+
|
||||
if (ops->rotate_font && ops->rotate_font(info, vc)) {
|
||||
ops->rotate = FB_ROTATE_UR;
|
||||
set_blitting_type(vc, info);
|
||||
@@ -1331,6 +1385,7 @@
|
||||
{
|
||||
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ int y;
|
||||
int c = scr_readw((u16 *) vc->vc_pos);
|
||||
|
||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
||||
@@ -1344,8 +1399,16 @@
|
||||
fbcon_add_cursor_timer(info);
|
||||
|
||||
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
|
||||
+ if (mode & CM_SOFTBACK) {
|
||||
+ mode &= ~CM_SOFTBACK;
|
||||
+ y = softback_lines;
|
||||
+ } else {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ y = 0;
|
||||
+ }
|
||||
|
||||
+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
|
||||
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
|
||||
get_color(vc, info, c, 0));
|
||||
}
|
||||
|
||||
@@ -1416,6 +1479,8 @@
|
||||
|
||||
if (con_is_visible(vc)) {
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +1618,99 @@
|
||||
scrollback_current = 0;
|
||||
}
|
||||
|
||||
+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
|
||||
+ long delta)
|
||||
+{
|
||||
+ int count = vc->vc_rows;
|
||||
+ unsigned short *d, *s;
|
||||
+ unsigned long n;
|
||||
+ int line = 0;
|
||||
+
|
||||
+ d = (u16 *) softback_curr;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ n = softback_curr + delta * vc->vc_size_row;
|
||||
+ softback_lines -= delta;
|
||||
+ if (delta < 0) {
|
||||
+ if (softback_curr < softback_top && n < softback_buf) {
|
||||
+ n += softback_end - softback_buf;
|
||||
+ if (n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else if (softback_curr >= softback_top
|
||||
+ && n < softback_top) {
|
||||
+ softback_lines -=
|
||||
+ (softback_top - n) / vc->vc_size_row;
|
||||
+ n = softback_top;
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (softback_curr > softback_in && n >= softback_end) {
|
||||
+ n += softback_buf - softback_end;
|
||||
+ if (n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ } else if (softback_curr <= softback_in && n > softback_in) {
|
||||
+ n = softback_in;
|
||||
+ softback_lines = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (n == softback_curr)
|
||||
+ return;
|
||||
+ softback_curr = n;
|
||||
+ s = (u16 *) softback_curr;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ while (count--) {
|
||||
+ unsigned short *start;
|
||||
+ unsigned short *le;
|
||||
+ unsigned short c;
|
||||
+ int x = 0;
|
||||
+ unsigned short attr = 1;
|
||||
+
|
||||
+ start = s;
|
||||
+ le = advance_row(s, 1);
|
||||
+ do {
|
||||
+ c = scr_readw(s);
|
||||
+ if (attr != (c & 0xff00)) {
|
||||
+ attr = c & 0xff00;
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start;
|
||||
+ start = s;
|
||||
+ }
|
||||
+ }
|
||||
+ if (c == scr_readw(d)) {
|
||||
+ if (s > start) {
|
||||
+ fbcon_putcs(vc, start, s - start,
|
||||
+ line, x);
|
||||
+ x += s - start + 1;
|
||||
+ start = s + 1;
|
||||
+ } else {
|
||||
+ x++;
|
||||
+ start++;
|
||||
+ }
|
||||
+ }
|
||||
+ s++;
|
||||
+ d++;
|
||||
+ } while (s < le);
|
||||
+ if (s > start)
|
||||
+ fbcon_putcs(vc, start, s - start, line, x);
|
||||
+ line++;
|
||||
+ if (d == (u16 *) softback_end)
|
||||
+ d = (u16 *) softback_buf;
|
||||
+ if (d == (u16 *) softback_in)
|
||||
+ d = (u16 *) vc->vc_origin;
|
||||
+ if (s == (u16 *) softback_end)
|
||||
+ s = (u16 *) softback_buf;
|
||||
+ if (s == (u16 *) softback_in)
|
||||
+ s = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
|
||||
int line, int count, int dy)
|
||||
{
|
||||
@@ -1692,6 +1850,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
|
||||
+ int count)
|
||||
+{
|
||||
+ unsigned short *p;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
|
||||
+
|
||||
+ while (count) {
|
||||
+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
|
||||
+ count--;
|
||||
+ p = advance_row(p, 1);
|
||||
+ softback_in += vc->vc_size_row;
|
||||
+ if (softback_in == softback_end)
|
||||
+ softback_in = softback_buf;
|
||||
+ if (softback_in == softback_top) {
|
||||
+ softback_top += vc->vc_size_row;
|
||||
+ if (softback_top == softback_end)
|
||||
+ softback_top = softback_buf;
|
||||
+ }
|
||||
+ }
|
||||
+ softback_curr = softback_in;
|
||||
+}
|
||||
+
|
||||
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int count)
|
||||
{
|
||||
@@ -1714,6 +1897,8 @@
|
||||
case SM_UP:
|
||||
if (count > vc->vc_rows) /* Maximum realistic size */
|
||||
count = vc->vc_rows;
|
||||
+ if (softback_top)
|
||||
+ fbcon_softback_note(vc, t, count);
|
||||
if (logo_shown >= 0)
|
||||
goto redraw_up;
|
||||
switch (p->scrollmode) {
|
||||
@@ -2084,6 +2269,14 @@
|
||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||
ops = info->fbcon_par;
|
||||
|
||||
+ if (softback_top) {
|
||||
+ if (softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+ softback_top = softback_curr = softback_in = softback_buf;
|
||||
+ softback_lines = 0;
|
||||
+ fbcon_update_softback(vc);
|
||||
+ }
|
||||
+
|
||||
if (logo_shown >= 0) {
|
||||
struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
|
||||
@@ -2407,6 +2600,9 @@
|
||||
int cnt;
|
||||
char *old_data = NULL;
|
||||
|
||||
+ if (con_is_visible(vc) && softback_lines)
|
||||
+ fbcon_set_origin(vc);
|
||||
+
|
||||
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
|
||||
if (p->userfont)
|
||||
old_data = vc->vc_font.data;
|
||||
@@ -2432,6 +2628,8 @@
|
||||
cols /= w;
|
||||
rows /= h;
|
||||
vc_resize(vc, cols, rows);
|
||||
+ if (con_is_visible(vc) && softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
} else if (con_is_visible(vc)
|
||||
&& vc->vc_mode == KD_TEXT) {
|
||||
fbcon_clear_margins(vc, 0);
|
||||
@@ -2590,7 +2788,19 @@
|
||||
|
||||
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
|
||||
{
|
||||
+ unsigned long p;
|
||||
+ int line;
|
||||
+
|
||||
+ if (vc->vc_num != fg_console || !softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset);
|
||||
+ line = offset / vc->vc_size_row;
|
||||
+ if (line >= softback_lines)
|
||||
+ return (u16 *) (vc->vc_origin + offset -
|
||||
+ softback_lines * vc->vc_size_row);
|
||||
+ p = softback_curr + offset;
|
||||
+ if (p >= softback_end)
|
||||
+ p += softback_buf - softback_end;
|
||||
+ return (u16 *) p;
|
||||
- return (u16 *) (vc->vc_origin + offset);
|
||||
}
|
||||
|
||||
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
|
||||
@@ -2604,7 +2814,22 @@
|
||||
|
||||
x = offset % vc->vc_cols;
|
||||
y = offset / vc->vc_cols;
|
||||
+ if (vc->vc_num == fg_console)
|
||||
+ y += softback_lines;
|
||||
ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ } else if (vc->vc_num == fg_console && softback_lines) {
|
||||
+ unsigned long offset = pos - softback_curr;
|
||||
+
|
||||
+ if (pos < softback_curr)
|
||||
+ offset += softback_end - softback_buf;
|
||||
+ offset /= 2;
|
||||
+ x = offset % vc->vc_cols;
|
||||
+ y = offset / vc->vc_cols;
|
||||
+ ret = pos + (vc->vc_cols - x) * 2;
|
||||
+ if (ret == softback_end)
|
||||
+ ret = softback_buf;
|
||||
+ if (ret == softback_in)
|
||||
+ ret = vc->vc_origin;
|
||||
} else {
|
||||
/* Should not happen */
|
||||
x = y = 0;
|
||||
@@ -2632,11 +2857,106 @@
|
||||
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
|
||||
(((a) & 0x0700) << 4);
|
||||
scr_writew(a, p++);
|
||||
+ if (p == (u16 *) softback_end)
|
||||
+ p = (u16 *) softback_buf;
|
||||
+ if (p == (u16 *) softback_in)
|
||||
+ p = (u16 *) vc->vc_origin;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void fbcon_scrolldelta(struct vc_data *vc, int lines)
|
||||
+{
|
||||
+ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
|
||||
+ struct fbcon_ops *ops = info->fbcon_par;
|
||||
+ struct fbcon_display *disp = &fb_display[fg_console];
|
||||
+ int offset, limit, scrollback_old;
|
||||
+
|
||||
+ if (softback_top) {
|
||||
+ if (vc->vc_num != fg_console)
|
||||
+ return;
|
||||
+ if (vc->vc_mode != KD_TEXT || !lines)
|
||||
+ return;
|
||||
+ if (logo_shown >= 0) {
|
||||
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
|
||||
+
|
||||
+ if (conp2->vc_top == logo_lines
|
||||
+ && conp2->vc_bottom == conp2->vc_rows)
|
||||
+ conp2->vc_top = 0;
|
||||
+ if (logo_shown == vc->vc_num) {
|
||||
+ unsigned long p, q;
|
||||
+ int i;
|
||||
+
|
||||
+ p = softback_in;
|
||||
+ q = vc->vc_origin +
|
||||
+ logo_lines * vc->vc_size_row;
|
||||
+ for (i = 0; i < logo_lines; i++) {
|
||||
+ if (p == softback_top)
|
||||
+ break;
|
||||
+ if (p == softback_buf)
|
||||
+ p = softback_end;
|
||||
+ p -= vc->vc_size_row;
|
||||
+ q -= vc->vc_size_row;
|
||||
+ scr_memcpyw((u16 *) q, (u16 *) p,
|
||||
+ vc->vc_size_row);
|
||||
+ }
|
||||
+ softback_in = softback_curr = p;
|
||||
+ update_region(vc, vc->vc_origin,
|
||||
+ logo_lines * vc->vc_cols);
|
||||
+ }
|
||||
+ logo_shown = FBCON_LOGO_CANSHOW;
|
||||
+ }
|
||||
+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
|
||||
+ fbcon_redraw_softback(vc, disp, lines);
|
||||
+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ if (!scrollback_phys_max)
|
||||
+ return;
|
||||
+
|
||||
+ scrollback_old = scrollback_current;
|
||||
+ scrollback_current -= lines;
|
||||
+ if (scrollback_current < 0)
|
||||
+ scrollback_current = 0;
|
||||
+ else if (scrollback_current > scrollback_max)
|
||||
+ scrollback_current = scrollback_max;
|
||||
+ if (scrollback_current == scrollback_old)
|
||||
+ return;
|
||||
+
|
||||
+ if (fbcon_is_inactive(vc, info))
|
||||
+ return;
|
||||
+
|
||||
+ fbcon_cursor(vc, CM_ERASE);
|
||||
+
|
||||
+ offset = disp->yscroll - scrollback_current;
|
||||
+ limit = disp->vrows;
|
||||
+ switch (disp->scrollmode) {
|
||||
+ case SCROLL_WRAP_MOVE:
|
||||
+ info->var.vmode |= FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ case SCROLL_PAN_MOVE:
|
||||
+ case SCROLL_PAN_REDRAW:
|
||||
+ limit -= vc->vc_rows;
|
||||
+ info->var.vmode &= ~FB_VMODE_YWRAP;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (offset < 0)
|
||||
+ offset += limit;
|
||||
+ else if (offset >= limit)
|
||||
+ offset -= limit;
|
||||
+
|
||||
+ ops->var.xoffset = 0;
|
||||
+ ops->var.yoffset = offset * vc->vc_font.height;
|
||||
+ ops->update_start(info);
|
||||
+
|
||||
+ if (!scrollback_current)
|
||||
+ fbcon_cursor(vc, CM_DRAW);
|
||||
}
|
||||
|
||||
static int fbcon_set_origin(struct vc_data *vc)
|
||||
{
|
||||
+ if (softback_lines)
|
||||
+ fbcon_scrolldelta(vc, softback_lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2700,6 +3020,8 @@
|
||||
|
||||
fbcon_set_palette(vc, color_table);
|
||||
update_screen(vc);
|
||||
+ if (softback_buf)
|
||||
+ fbcon_update_softback(vc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3110,6 +3432,7 @@
|
||||
.con_font_default = fbcon_set_def_font,
|
||||
.con_font_copy = fbcon_copy_font,
|
||||
.con_set_palette = fbcon_set_palette,
|
||||
+ .con_scrolldelta = fbcon_scrolldelta,
|
||||
.con_set_origin = fbcon_set_origin,
|
||||
.con_invert_region = fbcon_invert_region,
|
||||
.con_screen_pos = fbcon_screen_pos,
|
||||
@@ -3344,6 +3667,9 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
+ kvfree((void *)softback_buf);
|
||||
+ softback_buf = 0UL;
|
||||
+
|
||||
for_each_registered_fb(i) {
|
||||
int pending = 0;
|
||||
|
@ -1,215 +0,0 @@
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
index 8c09c306ff67..07e3a4eab811 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -155,6 +155,7 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
for (i = 0; i < fp->header->num_pics; i++) {
|
||||
struct splash_blob_priv *bp;
|
||||
struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+ const struct splash_pic_header *ph = pp->pic_header;
|
||||
long dst_xoff, dst_yoff;
|
||||
|
||||
if (pp->blobs_loaded < 1)
|
||||
@@ -165,8 +166,139 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
if (!bp || bp->blob_header->type != 0)
|
||||
continue;
|
||||
|
||||
- dst_xoff = (info->var.xres - pp->pic_header->width) / 2;
|
||||
- dst_yoff = (info->var.yres - pp->pic_header->height) / 2;
|
||||
+ switch (ph->position) {
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_LEFT:
|
||||
+ dst_xoff = 0;
|
||||
+ dst_yoff = 0;
|
||||
+
|
||||
+ dst_xoff += ph->position_offset;
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = 0;
|
||||
+
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_TOP_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_yoff = 0;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ dst_yoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+
|
||||
+ dst_yoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_BOTTOM_LEFT:
|
||||
+ dst_xoff = 0 + ph->position_offset;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height
|
||||
+ - ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_POS_FLAG_CORNER | SPLASH_CORNER_LEFT:
|
||||
+ dst_xoff = 0;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff += ph->position_offset;
|
||||
+ break;
|
||||
+
|
||||
+ case SPLASH_CORNER_TOP_LEFT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ dst_yoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_TOP:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_yoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_TOP_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff += ph->position_offset;
|
||||
+ dst_yoff -= ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_BOTTOM_RIGHT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff += ph->position_offset;
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_BOTTOM:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_BOTTOM_LEFT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ dst_yoff += ph->position_offset;
|
||||
+ break;
|
||||
+ case SPLASH_CORNER_LEFT:
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+
|
||||
+ dst_xoff -= ph->position_offset;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ /* As a fallback, center the picture. */
|
||||
+ dst_xoff = info->var.xres - pp->pic_header->width;
|
||||
+ dst_xoff /= 2;
|
||||
+ dst_yoff = info->var.yres - pp->pic_header->height;
|
||||
+ dst_yoff /= 2;
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
if (dst_xoff < 0
|
||||
|| dst_yoff < 0
|
||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
||||
index 89dc9cca8f0c..71cedcc68933 100644
|
||||
--- a/include/uapi/linux/bootsplash_file.h
|
||||
+++ b/include/uapi/linux/bootsplash_file.h
|
||||
@@ -91,7 +91,32 @@ struct splash_pic_header {
|
||||
*/
|
||||
uint8_t num_blobs;
|
||||
|
||||
- uint8_t padding[27];
|
||||
+ /*
|
||||
+ * Corner to move the picture to / from.
|
||||
+ * 0x00 - Top left
|
||||
+ * 0x01 - Top
|
||||
+ * 0x02 - Top right
|
||||
+ * 0x03 - Right
|
||||
+ * 0x04 - Bottom right
|
||||
+ * 0x05 - Bottom
|
||||
+ * 0x06 - Bottom left
|
||||
+ * 0x07 - Left
|
||||
+ *
|
||||
+ * Flags:
|
||||
+ * 0x10 - Calculate offset from the corner towards the center,
|
||||
+ * rather than from the center towards the corner
|
||||
+ */
|
||||
+ uint8_t position;
|
||||
+
|
||||
+ /*
|
||||
+ * Pixel offset from the selected position.
|
||||
+ * Example: If the picture is in the top right corner, it will
|
||||
+ * be placed position_offset pixels from the top and
|
||||
+ * position_offset pixels from the right margin.
|
||||
+ */
|
||||
+ uint16_t position_offset;
|
||||
+
|
||||
+ uint8_t padding[24];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
@@ -115,4 +140,22 @@ struct splash_blob_header {
|
||||
uint8_t padding[9];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
+
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Enums for on-disk types
|
||||
+ */
|
||||
+enum splash_position {
|
||||
+ SPLASH_CORNER_TOP_LEFT = 0,
|
||||
+ SPLASH_CORNER_TOP = 1,
|
||||
+ SPLASH_CORNER_TOP_RIGHT = 2,
|
||||
+ SPLASH_CORNER_RIGHT = 3,
|
||||
+ SPLASH_CORNER_BOTTOM_RIGHT = 4,
|
||||
+ SPLASH_CORNER_BOTTOM = 5,
|
||||
+ SPLASH_CORNER_BOTTOM_LEFT = 6,
|
||||
+ SPLASH_CORNER_LEFT = 7,
|
||||
+ SPLASH_POS_FLAG_CORNER = 0x10,
|
||||
+};
|
||||
+
|
||||
#endif
|
@ -1,58 +0,0 @@
|
||||
From a163474e9b86c2c25f20733385d8b1d6de492a7f Mon Sep 17 00:00:00 2001
|
||||
From: Ard Biesheuvel <ardb@kernel.org>
|
||||
Date: Wed, 25 Nov 2020 08:45:55 +0100
|
||||
Subject: efivarfs: revert "fix memory leak in efivarfs_create()"
|
||||
|
||||
The memory leak addressed by commit fe5186cf12e3 is a false positive:
|
||||
all allocations are recorded in a linked list, and freed when the
|
||||
filesystem is unmounted. This leads to double frees, and as reported
|
||||
by David, leads to crashes if SLUB is configured to self destruct when
|
||||
double frees occur.
|
||||
|
||||
So drop the redundant kfree() again, and instead, mark the offending
|
||||
pointer variable so the allocation is ignored by kmemleak.
|
||||
|
||||
Cc: Vamshi K Sthambamkadi <vamshi.k.sthambamkadi@gmail.com>
|
||||
Fixes: fe5186cf12e3 ("efivarfs: fix memory leak in efivarfs_create()")
|
||||
Reported-by: David Laight <David.Laight@aculab.com>
|
||||
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
|
||||
---
|
||||
fs/efivarfs/inode.c | 2 ++
|
||||
fs/efivarfs/super.c | 1 -
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
|
||||
index 96c0c86f3fff..0297ad95eb5c 100644
|
||||
--- a/fs/efivarfs/inode.c
|
||||
+++ b/fs/efivarfs/inode.c
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/efi.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ctype.h>
|
||||
+#include <linux/kmemleak.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
@@ -103,6 +104,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
|
||||
var->var.VariableName[i] = '\0';
|
||||
|
||||
inode->i_private = var;
|
||||
+ kmemleak_ignore(var);
|
||||
|
||||
err = efivar_entry_add(var, &efivarfs_list);
|
||||
if (err)
|
||||
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
|
||||
index f943fd0b0699..15880a68faad 100644
|
||||
--- a/fs/efivarfs/super.c
|
||||
+++ b/fs/efivarfs/super.c
|
||||
@@ -21,7 +21,6 @@ LIST_HEAD(efivarfs_list);
|
||||
static void efivarfs_evict_inode(struct inode *inode)
|
||||
{
|
||||
clear_inode(inode);
|
||||
- kfree(inode->i_private);
|
||||
}
|
||||
|
||||
static const struct super_operations efivarfs_ops = {
|
||||
--
|
||||
cgit v1.2.3-1-gf6bb5
|
||||
|
@ -1,327 +0,0 @@
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
index 815b007f81ca..c8642142cfea 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -53,6 +53,14 @@ static void splash_callback_redraw_vc(struct work_struct *ignored)
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
+static void splash_callback_animation(struct work_struct *ignored)
|
||||
+{
|
||||
+ if (bootsplash_would_render_now()) {
|
||||
+ /* This will also re-schedule this delayed worker */
|
||||
+ splash_callback_redraw_vc(ignored);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
|
||||
static bool is_fb_compatible(const struct fb_info *info)
|
||||
{
|
||||
@@ -103,17 +111,44 @@ static bool is_fb_compatible(const struct fb_info *info)
|
||||
*/
|
||||
void bootsplash_render_full(struct fb_info *info)
|
||||
{
|
||||
+ bool is_update = false;
|
||||
+
|
||||
mutex_lock(&splash_state.data_lock);
|
||||
|
||||
- if (!is_fb_compatible(info))
|
||||
- goto out;
|
||||
+ /*
|
||||
+ * If we've painted on this FB recently, we don't have to do
|
||||
+ * the sanity checks and background drawing again.
|
||||
+ */
|
||||
+ if (splash_state.splash_fb == info)
|
||||
+ is_update = true;
|
||||
+
|
||||
+
|
||||
+ if (!is_update) {
|
||||
+ /* Check whether we actually support this FB. */
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+
|
||||
+ if (!is_fb_compatible(info))
|
||||
+ goto out;
|
||||
+
|
||||
+ /* Draw the background only once */
|
||||
+ bootsplash_do_render_background(info, splash_state.file);
|
||||
|
||||
- bootsplash_do_render_background(info, splash_state.file);
|
||||
+ /* Mark this FB as last seen */
|
||||
+ splash_state.splash_fb = info;
|
||||
+ }
|
||||
|
||||
- bootsplash_do_render_pictures(info, splash_state.file);
|
||||
+ bootsplash_do_render_pictures(info, splash_state.file, is_update);
|
||||
|
||||
bootsplash_do_render_flush(info);
|
||||
|
||||
+ bootsplash_do_step_animations(splash_state.file);
|
||||
+
|
||||
+ /* Schedule update for animated splash screens */
|
||||
+ if (splash_state.file->frame_ms > 0)
|
||||
+ schedule_delayed_work(&splash_state.dwork_animation,
|
||||
+ msecs_to_jiffies(
|
||||
+ splash_state.file->frame_ms));
|
||||
+
|
||||
out:
|
||||
mutex_unlock(&splash_state.data_lock);
|
||||
}
|
||||
@@ -169,8 +204,14 @@ void bootsplash_enable(void)
|
||||
|
||||
was_enabled = test_and_set_bit(0, &splash_state.enabled);
|
||||
|
||||
- if (!was_enabled)
|
||||
+ if (!was_enabled) {
|
||||
+ /* Force a full redraw when the splash is re-activated */
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+
|
||||
schedule_work(&splash_state.work_redraw_vc);
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +268,14 @@ ATTRIBUTE_GROUPS(splash_dev);
|
||||
*/
|
||||
static int splash_resume(struct device *device)
|
||||
{
|
||||
+ /*
|
||||
+ * Force full redraw on resume since we've probably lost the
|
||||
+ * framebuffer's contents meanwhile
|
||||
+ */
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+
|
||||
if (bootsplash_would_render_now())
|
||||
schedule_work(&splash_state.work_redraw_vc);
|
||||
|
||||
@@ -235,6 +284,7 @@ static int splash_resume(struct device *device)
|
||||
|
||||
static int splash_suspend(struct device *device)
|
||||
{
|
||||
+ cancel_delayed_work_sync(&splash_state.dwork_animation);
|
||||
cancel_work_sync(&splash_state.work_redraw_vc);
|
||||
|
||||
return 0;
|
||||
@@ -296,6 +346,8 @@ void bootsplash_init(void)
|
||||
set_bit(0, &splash_state.enabled);
|
||||
|
||||
INIT_WORK(&splash_state.work_redraw_vc, splash_callback_redraw_vc);
|
||||
+ INIT_DELAYED_WORK(&splash_state.dwork_animation,
|
||||
+ splash_callback_animation);
|
||||
|
||||
|
||||
if (!splash_state.bootfile || !strlen(splash_state.bootfile))
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_internal.h b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
index 0acb383aa4e3..b3a74835d90f 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_internal.h
|
||||
@@ -37,6 +37,8 @@ struct splash_pic_priv {
|
||||
|
||||
struct splash_blob_priv *blobs;
|
||||
u16 blobs_loaded;
|
||||
+
|
||||
+ u16 anim_nextframe;
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +47,12 @@ struct splash_file_priv {
|
||||
const struct splash_file_header *header;
|
||||
|
||||
struct splash_pic_priv *pics;
|
||||
+
|
||||
+ /*
|
||||
+ * A local copy of the frame delay in the header.
|
||||
+ * We modify it to keep the code simple.
|
||||
+ */
|
||||
+ u16 frame_ms;
|
||||
};
|
||||
|
||||
|
||||
@@ -71,6 +79,7 @@ struct splash_priv {
|
||||
struct platform_device *splash_device;
|
||||
|
||||
struct work_struct work_redraw_vc;
|
||||
+ struct delayed_work dwork_animation;
|
||||
|
||||
/* Splash data structures including lock for everything below */
|
||||
struct mutex data_lock;
|
||||
@@ -88,8 +97,10 @@ struct splash_priv {
|
||||
void bootsplash_do_render_background(struct fb_info *info,
|
||||
const struct splash_file_priv *fp);
|
||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
- const struct splash_file_priv *fp);
|
||||
+ const struct splash_file_priv *fp,
|
||||
+ bool is_update);
|
||||
void bootsplash_do_render_flush(struct fb_info *info);
|
||||
+void bootsplash_do_step_animations(struct splash_file_priv *fp);
|
||||
|
||||
|
||||
void bootsplash_free_file(struct splash_file_priv *fp);
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_load.c b/drivers/video/fbdev/core/bootsplash_load.c
|
||||
index fd807571ab7d..1f661b2d4cc9 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_load.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_load.c
|
||||
@@ -71,6 +71,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct splash_file_priv *fp;
|
||||
+ bool have_anim = false;
|
||||
unsigned int i;
|
||||
const u8 *walker;
|
||||
|
||||
@@ -135,6 +136,13 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
goto err;
|
||||
}
|
||||
|
||||
+ if (ph->anim_type > SPLASH_ANIM_LOOP_FORWARD) {
|
||||
+ pr_warn("Picture %u: Unsupported animation type %u.\n",
|
||||
+ i, ph->anim_type);
|
||||
+
|
||||
+ ph->anim_type = SPLASH_ANIM_NONE;
|
||||
+ }
|
||||
+
|
||||
pp->pic_header = ph;
|
||||
pp->blobs = vzalloc(ph->num_blobs
|
||||
* sizeof(struct splash_blob_priv));
|
||||
@@ -202,6 +210,7 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
/* Walk over pictures and ensure all blob slots are filled */
|
||||
for (i = 0; i < fp->header->num_pics; i++) {
|
||||
struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+ const struct splash_pic_header *ph = pp->pic_header;
|
||||
|
||||
if (pp->blobs_loaded != pp->pic_header->num_blobs) {
|
||||
pr_err("Picture %u doesn't have all blob slots filled.\n",
|
||||
@@ -209,8 +218,20 @@ struct splash_file_priv *bootsplash_load_firmware(struct device *device,
|
||||
|
||||
goto err;
|
||||
}
|
||||
+
|
||||
+ if (ph->anim_type
|
||||
+ && ph->num_blobs > 1
|
||||
+ && ph->anim_loop < pp->blobs_loaded)
|
||||
+ have_anim = true;
|
||||
}
|
||||
|
||||
+ if (!have_anim)
|
||||
+ /* Disable animation timer if there is nothing to animate */
|
||||
+ fp->frame_ms = 0;
|
||||
+ else
|
||||
+ /* Enforce minimum delay between frames */
|
||||
+ fp->frame_ms = max((u16)20, fp->header->frame_ms);
|
||||
+
|
||||
pr_info("Loaded (%ld bytes, %u pics, %u blobs).\n",
|
||||
fw->size,
|
||||
fp->header->num_pics,
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash_render.c b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
index 07e3a4eab811..76033606ca8a 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash_render.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash_render.c
|
||||
@@ -148,7 +148,8 @@ void bootsplash_do_render_background(struct fb_info *info,
|
||||
|
||||
|
||||
void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
- const struct splash_file_priv *fp)
|
||||
+ const struct splash_file_priv *fp,
|
||||
+ bool is_update)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
@@ -161,7 +162,11 @@ void bootsplash_do_render_pictures(struct fb_info *info,
|
||||
if (pp->blobs_loaded < 1)
|
||||
continue;
|
||||
|
||||
- bp = &pp->blobs[0];
|
||||
+ /* Skip static pictures when refreshing animations */
|
||||
+ if (ph->anim_type == SPLASH_ANIM_NONE && is_update)
|
||||
+ continue;
|
||||
+
|
||||
+ bp = &pp->blobs[pp->anim_nextframe];
|
||||
|
||||
if (!bp || bp->blob_header->type != 0)
|
||||
continue;
|
||||
@@ -351,3 +356,24 @@ void bootsplash_do_render_flush(struct fb_info *info)
|
||||
info->fbops->fb_copyarea(info, &area);
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+void bootsplash_do_step_animations(struct splash_file_priv *fp)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ /* Step every animation once */
|
||||
+ for (i = 0; i < fp->header->num_pics; i++) {
|
||||
+ struct splash_pic_priv *pp = &fp->pics[i];
|
||||
+
|
||||
+ if (pp->blobs_loaded < 2
|
||||
+ || pp->pic_header->anim_loop > pp->blobs_loaded)
|
||||
+ continue;
|
||||
+
|
||||
+ if (pp->pic_header->anim_type == SPLASH_ANIM_LOOP_FORWARD) {
|
||||
+ pp->anim_nextframe++;
|
||||
+ if (pp->anim_nextframe >= pp->pic_header->num_blobs)
|
||||
+ pp->anim_nextframe = pp->pic_header->anim_loop;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/include/uapi/linux/bootsplash_file.h b/include/uapi/linux/bootsplash_file.h
|
||||
index 71cedcc68933..b3af0a3c6487 100644
|
||||
--- a/include/uapi/linux/bootsplash_file.h
|
||||
+++ b/include/uapi/linux/bootsplash_file.h
|
||||
@@ -77,7 +77,17 @@ struct splash_file_header {
|
||||
uint16_t num_blobs;
|
||||
uint8_t num_pics;
|
||||
|
||||
- uint8_t padding[103];
|
||||
+ uint8_t unused_1;
|
||||
+
|
||||
+ /*
|
||||
+ * Milliseconds to wait before painting the next frame in
|
||||
+ * an animation.
|
||||
+ * This is actually a minimum, as the system is allowed to
|
||||
+ * stall for longer between frames.
|
||||
+ */
|
||||
+ uint16_t frame_ms;
|
||||
+
|
||||
+ uint8_t padding[100];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
@@ -116,7 +126,23 @@ struct splash_pic_header {
|
||||
*/
|
||||
uint16_t position_offset;
|
||||
|
||||
- uint8_t padding[24];
|
||||
+ /*
|
||||
+ * Animation type.
|
||||
+ * 0 - off
|
||||
+ * 1 - forward loop
|
||||
+ */
|
||||
+ uint8_t anim_type;
|
||||
+
|
||||
+ /*
|
||||
+ * Animation loop point.
|
||||
+ * Actual meaning depends on animation type:
|
||||
+ * Type 0 - Unused
|
||||
+ * 1 - Frame at which to restart the forward loop
|
||||
+ * (allowing for "intro" frames)
|
||||
+ */
|
||||
+ uint8_t anim_loop;
|
||||
+
|
||||
+ uint8_t padding[22];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
@@ -158,4 +184,9 @@ enum splash_position {
|
||||
SPLASH_POS_FLAG_CORNER = 0x10,
|
||||
};
|
||||
|
||||
+enum splash_anim_type {
|
||||
+ SPLASH_ANIM_NONE = 0,
|
||||
+ SPLASH_ANIM_LOOP_FORWARD = 1,
|
||||
+};
|
||||
+
|
||||
#endif
|
@ -1,82 +0,0 @@
|
||||
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
|
||||
index 2ebaba16f785..416735ab6dc1 100644
|
||||
--- a/drivers/tty/vt/vt.c
|
||||
+++ b/drivers/tty/vt/vt.c
|
||||
@@ -105,6 +105,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/gcd.h>
|
||||
+#include <linux/bootsplash.h>
|
||||
|
||||
#define MAX_NR_CON_DRIVER 16
|
||||
|
||||
@@ -4235,6 +4236,7 @@ void do_unblank_screen(int leaving_gfx)
|
||||
}
|
||||
|
||||
console_blanked = 0;
|
||||
+ bootsplash_mark_dirty();
|
||||
if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
|
||||
/* Low-level driver cannot restore -> do it ourselves */
|
||||
update_screen(vc);
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
index c8642142cfea..13fcaabbc2ca 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -165,6 +165,13 @@ bool bootsplash_would_render_now(void)
|
||||
&& bootsplash_is_enabled();
|
||||
}
|
||||
|
||||
+void bootsplash_mark_dirty(void)
|
||||
+{
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+}
|
||||
+
|
||||
bool bootsplash_is_enabled(void)
|
||||
{
|
||||
bool was_enabled;
|
||||
@@ -206,9 +213,7 @@ void bootsplash_enable(void)
|
||||
|
||||
if (!was_enabled) {
|
||||
/* Force a full redraw when the splash is re-activated */
|
||||
- mutex_lock(&splash_state.data_lock);
|
||||
- splash_state.splash_fb = NULL;
|
||||
- mutex_unlock(&splash_state.data_lock);
|
||||
+ bootsplash_mark_dirty();
|
||||
|
||||
schedule_work(&splash_state.work_redraw_vc);
|
||||
}
|
||||
@@ -272,9 +277,7 @@ static int splash_resume(struct device *device)
|
||||
* Force full redraw on resume since we've probably lost the
|
||||
* framebuffer's contents meanwhile
|
||||
*/
|
||||
- mutex_lock(&splash_state.data_lock);
|
||||
- splash_state.splash_fb = NULL;
|
||||
- mutex_unlock(&splash_state.data_lock);
|
||||
+ bootsplash_mark_dirty();
|
||||
|
||||
if (bootsplash_would_render_now())
|
||||
schedule_work(&splash_state.work_redraw_vc);
|
||||
diff --git a/include/linux/bootsplash.h b/include/linux/bootsplash.h
|
||||
index c6dd0b43180d..4075098aaadd 100644
|
||||
--- a/include/linux/bootsplash.h
|
||||
+++ b/include/linux/bootsplash.h
|
||||
@@ -19,6 +19,8 @@ extern void bootsplash_render_full(struct fb_info *info);
|
||||
|
||||
extern bool bootsplash_would_render_now(void);
|
||||
|
||||
+extern void bootsplash_mark_dirty(void);
|
||||
+
|
||||
extern bool bootsplash_is_enabled(void);
|
||||
extern void bootsplash_disable(void);
|
||||
extern void bootsplash_enable(void);
|
||||
@@ -31,6 +33,8 @@ extern void bootsplash_init(void);
|
||||
|
||||
#define bootsplash_would_render_now() (false)
|
||||
|
||||
+#define bootsplash_mark_dirty()
|
||||
+
|
||||
#define bootsplash_is_enabled() (false)
|
||||
#define bootsplash_disable()
|
||||
#define bootsplash_enable()
|
@ -1,42 +0,0 @@
|
||||
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
|
||||
index f4166263bb3a..a248429194bb 100644
|
||||
--- a/drivers/tty/vt/keyboard.c
|
||||
+++ b/drivers/tty/vt/keyboard.c
|
||||
@@ -49,6 +49,8 @@
|
||||
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
+#include <linux/bootsplash.h>
|
||||
+
|
||||
/*
|
||||
* Exported functions/variables
|
||||
*/
|
||||
@@ -1413,6 +1415,28 @@ static void kbd_keycode(unsigned int key
|
||||
}
|
||||
#endif
|
||||
|
||||
+ /* Trap keys when bootsplash is shown */
|
||||
+ if (bootsplash_would_render_now()) {
|
||||
+ /* Deactivate bootsplash on ESC or Alt+Fxx VT switch */
|
||||
+ if (keycode >= KEY_F1 && keycode <= KEY_F12) {
|
||||
+ bootsplash_disable();
|
||||
+
|
||||
+ /*
|
||||
+ * No return here since we want to actually
|
||||
+ * perform the VT switch.
|
||||
+ */
|
||||
+ } else {
|
||||
+ if (keycode == KEY_ESC)
|
||||
+ bootsplash_disable();
|
||||
+
|
||||
+ /*
|
||||
+ * Just drop any other keys.
|
||||
+ * Their effect would be hidden by the splash.
|
||||
+ */
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (kbd->kbdmode == VC_MEDIUMRAW) {
|
||||
/*
|
||||
* This is extended medium raw mode, with keys above 127
|
@ -1,21 +0,0 @@
|
||||
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
|
||||
index 3ffc1ce29023..bc6a24c9dfa8 100644
|
||||
--- a/drivers/tty/sysrq.c
|
||||
+++ b/drivers/tty/sysrq.c
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/rcupdate.h>
|
||||
+#include <linux/bootsplash.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/irq_regs.h>
|
||||
@@ -104,6 +105,8 @@ static void sysrq_handle_SAK(int key)
|
||||
{
|
||||
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
|
||||
schedule_work(SAK_work);
|
||||
+
|
||||
+ bootsplash_disable();
|
||||
}
|
||||
static struct sysrq_key_op sysrq_SAK_op = {
|
||||
.handler = sysrq_handle_SAK,
|
@ -1,21 +0,0 @@
|
||||
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
|
||||
index 9a39a6fcfe98..8a9c67e1c5d8 100644
|
||||
--- a/drivers/video/fbdev/core/fbcon.c
|
||||
+++ b/drivers/video/fbdev/core/fbcon.c
|
||||
@@ -1343,6 +1343,16 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
||||
int y;
|
||||
int c = scr_readw((u16 *) vc->vc_pos);
|
||||
|
||||
+ /*
|
||||
+ * Disable the splash here so we don't have to hook into
|
||||
+ * vt_console_print() in drivers/tty/vt/vt.c
|
||||
+ *
|
||||
+ * We'd disable the splash just before the call to
|
||||
+ * hide_cursor() anyway, so this spot is just fine.
|
||||
+ */
|
||||
+ if (oops_in_progress)
|
||||
+ bootsplash_disable();
|
||||
+
|
||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
||||
|
||||
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
|
@ -1,321 +0,0 @@
|
||||
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
new file mode 100644
|
||||
index 000000000000..742c7b035ded
|
||||
--- /dev/null
|
||||
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
@@ -0,0 +1,11 @@
|
||||
+What: /sys/devices/platform/bootsplash.0/enabled
|
||||
+Date: Oct 2017
|
||||
+KernelVersion: 4.14
|
||||
+Contact: Max Staudt <mstaudt@suse.de>
|
||||
+Description:
|
||||
+ Can be set and read.
|
||||
+
|
||||
+ 0: Splash is disabled.
|
||||
+ 1: Splash is shown whenever fbcon would show a text console
|
||||
+ (i.e. no graphical application is running), and a splash
|
||||
+ file is loaded.
|
||||
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
|
||||
new file mode 100644
|
||||
index 000000000000..611f0c558925
|
||||
--- /dev/null
|
||||
+++ b/Documentation/bootsplash.rst
|
||||
@@ -0,0 +1,285 @@
|
||||
+====================
|
||||
+The Linux bootsplash
|
||||
+====================
|
||||
+
|
||||
+:Date: November, 2017
|
||||
+:Author: Max Staudt <mstaudt@suse.de>
|
||||
+
|
||||
+
|
||||
+The Linux bootsplash is a graphical replacement for the '``quiet``' boot
|
||||
+option, typically showing a logo and a spinner animation as the system starts.
|
||||
+
|
||||
+Currently, it is a part of the Framebuffer Console support, and can be found
|
||||
+as ``CONFIG_BOOTSPLASH`` in the kernel configuration. This means that as long
|
||||
+as it is enabled, it hijacks fbcon's output and draws a splash screen instead.
|
||||
+
|
||||
+Purely compiling in the bootsplash will not render it functional - to actually
|
||||
+render a splash, you will also need a splash theme file. See the example
|
||||
+utility and script in ``tools/bootsplash`` for a live demo.
|
||||
+
|
||||
+
|
||||
+
|
||||
+Motivation
|
||||
+==========
|
||||
+
|
||||
+- The '``quiet``' boot option only suppresses most messages during boot, but
|
||||
+ errors are still shown.
|
||||
+
|
||||
+- A user space implementation can only show a logo once user space has been
|
||||
+ initialized far enough to allow this. A kernel splash can display a splash
|
||||
+ immediately as soon as fbcon can be displayed.
|
||||
+
|
||||
+- Implementing a splash screen in user space (e.g. Plymouth) is problematic
|
||||
+ due to resource conflicts.
|
||||
+
|
||||
+ For example, if Plymouth is keeping ``/dev/fb0`` (provided via vesafb/efifb)
|
||||
+ open, then most DRM drivers can't replace it because the address space is
|
||||
+ still busy - thus leading to a VRAM reservation error.
|
||||
+
|
||||
+ See: https://bugzilla.opensuse.org/show_bug.cgi?id=980750
|
||||
+
|
||||
+
|
||||
+
|
||||
+Command line arguments
|
||||
+======================
|
||||
+
|
||||
+``bootsplash.bootfile``
|
||||
+ Which file in the initramfs to load.
|
||||
+
|
||||
+ The splash theme is loaded via request_firmware(), thus to load
|
||||
+ ``/lib/firmware/bootsplash/mytheme`` pass the command line:
|
||||
+
|
||||
+ ``bootsplash.bootfile=bootsplash/mytheme``
|
||||
+
|
||||
+ Note: The splash file *has to be* in the initramfs, as it needs to be
|
||||
+ available when the splash is initialized early on.
|
||||
+
|
||||
+ Default: none, i.e. a non-functional splash, falling back to showing text.
|
||||
+
|
||||
+
|
||||
+
|
||||
+sysfs run-time configuration
|
||||
+============================
|
||||
+
|
||||
+``/sys/devices/platform/bootsplash.0/enabled``
|
||||
+ Enable/disable the bootsplash.
|
||||
+ The system boots with this set to 1, but will not show a splash unless
|
||||
+ a splash theme file is also loaded.
|
||||
+
|
||||
+
|
||||
+
|
||||
+Kconfig
|
||||
+=======
|
||||
+
|
||||
+``BOOTSPLASH``
|
||||
+ Whether to compile in bootsplash support
|
||||
+ (depends on fbcon compiled in, i.e. ``FRAMEBUFFER_CONSOLE=y``)
|
||||
+
|
||||
+
|
||||
+
|
||||
+Bootsplash file format
|
||||
+======================
|
||||
+
|
||||
+A file specified in the kernel configuration as ``CONFIG_BOOTSPLASH_FILE``
|
||||
+or specified on the command line as ``bootsplash.bootfile`` will be loaded
|
||||
+and displayed as soon as fbcon is initialized.
|
||||
+
|
||||
+
|
||||
+Main blocks
|
||||
+-----------
|
||||
+
|
||||
+There are 3 main blocks in each file:
|
||||
+
|
||||
+ - one File header
|
||||
+ - n Picture headers
|
||||
+ - m (Blob header + payload) blocks
|
||||
+
|
||||
+
|
||||
+Structures
|
||||
+----------
|
||||
+
|
||||
+The on-disk structures are defined in
|
||||
+``drivers/video/fbdev/core/bootsplash_file.h`` and represent these blocks:
|
||||
+
|
||||
+ - ``struct splash_file_header``
|
||||
+
|
||||
+ Represents the file header, with splash-wide information including:
|
||||
+
|
||||
+ - The magic string "``Linux bootsplash``" on big-endian platforms
|
||||
+ (the reverse on little endian)
|
||||
+ - The file format version (for incompatible updates, hopefully never)
|
||||
+ - The background color
|
||||
+ - Number of picture and blob blocks
|
||||
+ - Animation speed (we only allow one delay for all animations)
|
||||
+
|
||||
+ The file header is followed by the first picture header.
|
||||
+
|
||||
+
|
||||
+ - ``struct splash_picture_header``
|
||||
+
|
||||
+ Represents an object (picture) drawn on screen, including its immutable
|
||||
+ properties:
|
||||
+ - Width, height
|
||||
+ - Positioning relative to screen corners or in the center
|
||||
+ - Animation, if any
|
||||
+ - Animation type
|
||||
+ - Number of blobs
|
||||
+
|
||||
+ The picture header is followed by another picture header, up until n
|
||||
+ picture headers (as defined in the file header) have been read. Then,
|
||||
+ the (blob header, payload) pairs follow.
|
||||
+
|
||||
+
|
||||
+ - ``struct splash_blob_header``
|
||||
+ (followed by payload)
|
||||
+
|
||||
+ Represents one raw data stream. So far, only picture data is defined.
|
||||
+
|
||||
+ The blob header is followed by a payload, then padding to n*16 bytes,
|
||||
+ then (if further blobs are defined in the file header) a further blob
|
||||
+ header.
|
||||
+
|
||||
+
|
||||
+Alignment
|
||||
+---------
|
||||
+
|
||||
+The bootsplash file is designed to be loaded into memory as-is.
|
||||
+
|
||||
+All structures are a multiple of 16 bytes long, all elements therein are
|
||||
+aligned to multiples of their length, and the payloads are always padded
|
||||
+up to multiples of 16 bytes. This is to allow aligned accesses in all
|
||||
+cases while still simply mapping the structures over an in-memory copy of
|
||||
+the bootsplash file.
|
||||
+
|
||||
+
|
||||
+Further information
|
||||
+-------------------
|
||||
+
|
||||
+Please see ``drivers/video/fbdev/core/bootsplash_file.h`` for further
|
||||
+details and possible values in the file.
|
||||
+
|
||||
+
|
||||
+
|
||||
+Hooks - how the bootsplash is integrated
|
||||
+========================================
|
||||
+
|
||||
+``drivers/video/fbdev/core/fbcon.c``
|
||||
+ ``fbcon_init()`` calls ``bootsplash_init()``, which loads the default
|
||||
+ bootsplash file or the one specified on the kernel command line.
|
||||
+
|
||||
+ ``fbcon_switch()`` draws the bootsplash when it's active, and is also
|
||||
+ one of the callers of ``set_blitting_type()``.
|
||||
+
|
||||
+ ``set_blitting_type()`` calls ``fbcon_set_dummyops()`` when the
|
||||
+ bootsplash is active, overriding the text rendering functions.
|
||||
+
|
||||
+ ``fbcon_cursor()`` will call ``bootsplash_disable()`` when an oops is
|
||||
+ being printed in order to make a kernel panic visible.
|
||||
+
|
||||
+``drivers/video/fbdev/core/dummyblit.c``
|
||||
+ This contains the dummy text rendering functions used to suppress text
|
||||
+ output while the bootsplash is shown.
|
||||
+
|
||||
+``drivers/tty/vt/keyboard.c``
|
||||
+ ``kbd_keycode()`` can call ``bootsplash_disable()`` when the user
|
||||
+ presses ESC or F1-F12 (changing VT). This is to provide a built-in way
|
||||
+ of disabling the splash manually at any time.
|
||||
+
|
||||
+
|
||||
+
|
||||
+FAQ: Frequently Asked Questions
|
||||
+===============================
|
||||
+
|
||||
+I want to see the log! How do I show the log?
|
||||
+---------------------------------------------
|
||||
+
|
||||
+Press ESC while the splash is shown, or remove the ``bootsplash.bootfile``
|
||||
+parameter from the kernel cmdline. Without that parameter, the bootsplash
|
||||
+will boot disabled.
|
||||
+
|
||||
+
|
||||
+Why use FB instead of modern DRM/KMS?
|
||||
+-------------------------------------
|
||||
+
|
||||
+This is a semantic problem:
|
||||
+ - What memory to draw the splash to?
|
||||
+ - And what mode will the screen be set to?
|
||||
+
|
||||
+Using the fbdev emulation solves these issues.
|
||||
+
|
||||
+Let's start from a bare KMS system, without fbcon, and without fbdev
|
||||
+emulation. In this case, as long as userspace doesn't open the KMS
|
||||
+device, the state of the screen is undefined. No framebuffer is
|
||||
+allocated in video RAM, and no particular mode is set.
|
||||
+
|
||||
+In this case, we'd have to allocate a framebuffer to show the splash,
|
||||
+and set our mode ourselves. This either wastes a screenful of video RAM
|
||||
+if the splash is to co-exist with the userspace program's own allocated
|
||||
+framebuffer, or there is a flicker as we deactivate and delete the
|
||||
+bootsplash's framebuffer and hand control over to userspace. Since we
|
||||
+may set a different mode than userspace, we'd also have flicker due
|
||||
+to mode switching.
|
||||
+
|
||||
+This logic is already contained in every KMS driver that performs fbdev
|
||||
+emulation. So we might as well use that. And the correct API to do so is
|
||||
+fbdev. Plus, we get compatibility with old, pure fbdev drivers for free.
|
||||
+With the fbdev emulation, there is *always* a well-defined framebuffer
|
||||
+to draw on. And the selection of mode has already been done by the
|
||||
+graphics driver, so we don't need to reinvent that wheel, either.
|
||||
+Finally, if userspace decides to use /dev/fbX, we don't have to worry
|
||||
+about wasting video RAM, either.
|
||||
+
|
||||
+
|
||||
+Why is the bootsplash integrated in fbcon?
|
||||
+------------------------------------------
|
||||
+
|
||||
+Right now, the bootsplash is drawn from within fbcon, as this allows us
|
||||
+to easily know *when* to draw - i.e. when we're safe from fbcon and
|
||||
+userspace drawing all over our beautiful splash logo.
|
||||
+
|
||||
+Separating them is not easy - see the to-do list below.
|
||||
+
|
||||
+
|
||||
+
|
||||
+TO DO list for future development
|
||||
+=================================
|
||||
+
|
||||
+Second enable/disable switch for the system
|
||||
+-------------------------------------------
|
||||
+
|
||||
+It may be helpful to differentiate between the system and the user
|
||||
+switching off the bootsplash. Thus, the system may make it disappear and
|
||||
+reappear e.g. for a password prompt, yet once the user has pressed ESC,
|
||||
+it could stay gone.
|
||||
+
|
||||
+
|
||||
+Fix buggy DRM/KMS drivers
|
||||
+-------------------------
|
||||
+
|
||||
+Currently, the splash code manually checks for fbdev emulation provided by
|
||||
+the ast, cirrus, and mgag200 DRM/KMS drivers.
|
||||
+These drivers use a manual mechanism similar to deferred I/O for their FB
|
||||
+emulation, and thus need to be manually flushed onto the screen in the same
|
||||
+way.
|
||||
+
|
||||
+This may be improved upon in several ways:
|
||||
+
|
||||
+1. Changing these drivers to expose the fbdev BO's memory directly, like
|
||||
+ bochsdrmfb does.
|
||||
+2. Creating a new fb_ops->fb_flush() API to allow the kernel to flush the
|
||||
+ framebuffer once the bootsplash has been drawn into it.
|
||||
+
|
||||
+
|
||||
+Separating from fbcon
|
||||
+---------------------
|
||||
+
|
||||
+Separating these two components would yield independence from fbcon being
|
||||
+compiled into the kernel, and thus lowering code size in embedded
|
||||
+applications.
|
||||
+
|
||||
+To do this cleanly will involve a clean separation of users of an FB device
|
||||
+within the kernel, i.e. fbcon, bootsplash, and userspace. Right now, the
|
||||
+legacy fbcon code and VT code co-operate to switch between fbcon and
|
||||
+userspace (by setting the VT into KD_GRAPHICS mode). Installing a muxer
|
||||
+between these components ensues refactoring of old code and checking for
|
||||
+correct locking.
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 5c237445761e..7ffac272434e 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2709,6 +2709,8 @@ BOOTSPLASH
|
||||
M: Max Staudt <mstaudt@suse.de>
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
S: Maintained
|
||||
+F: Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
+F: Documentation/bootsplash.rst
|
||||
F: drivers/video/fbdev/core/bootsplash*.*
|
||||
F: drivers/video/fbdev/core/dummycon.c
|
||||
F: include/linux/bootsplash.h
|
@ -1,56 +0,0 @@
|
||||
From 05044b9e4e4ae03f66e1c504d6fef57a1d135897 Mon Sep 17 00:00:00 2001
|
||||
From: Dylan Van Assche <me@dylanvanassche.be>
|
||||
Date: Thu, 24 Dec 2020 19:57:12 +0100
|
||||
Subject: [PATCH] dts: pinephone: Add 'pine64,pinephone' to compat list
|
||||
|
||||
Indicates that all PinePhone models share most of the hardware with each other.
|
||||
Used for feedbackd configuration when retrieving a device specific config for
|
||||
haptic feedbackd.
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts | 2 +-
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts | 2 +-
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts | 2 +-
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
index 0f6faa44c..2e0892b32 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/ {
|
||||
model = "Pine64 PinePhone Developer Batch (1.0)";
|
||||
- compatible = "pine64,pinephone-1.0", "allwinner,sun50i-a64";
|
||||
+ compatible = "pine64,pinephone-1.0", "pine64,pinephone", "allwinner,sun50i-a64";
|
||||
|
||||
reg_vbus: usb0-vbus {
|
||||
compatible = "regulator-fixed";
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
index 95a880fdc..d6bad0838 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/ {
|
||||
model = "Pine64 PinePhone Braveheart (1.1)";
|
||||
- compatible = "pine64,pinephone-1.1", "allwinner,sun50i-a64";
|
||||
+ compatible = "pine64,pinephone-1.1", "pine64,pinephone", "allwinner,sun50i-a64";
|
||||
|
||||
reg_vbus: usb0-vbus {
|
||||
compatible = "regulator-fixed";
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
index 23ba72508..710493186 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
/ {
|
||||
model = "Pine64 PinePhone (1.2)";
|
||||
- compatible = "pine64,pinephone-1.2", "allwinner,sun50i-a64";
|
||||
+ compatible = "pine64,pinephone-1.2", "pine64,pinephone", "allwinner,sun50i-a64";
|
||||
|
||||
wifi_pwrseq: wifi-pwrseq {
|
||||
compatible = "mmc-pwrseq-simple";
|
||||
--
|
||||
2.26.2
|
||||
|
@ -1,129 +0,0 @@
|
||||
diff --git a/Documentation/ABI/testing/sysfs-platform-bootsplash b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
index 742c7b035ded..f8f4b259220e 100644
|
||||
--- a/Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
+++ b/Documentation/ABI/testing/sysfs-platform-bootsplash
|
||||
@@ -9,3 +9,35 @@ Description:
|
||||
1: Splash is shown whenever fbcon would show a text console
|
||||
(i.e. no graphical application is running), and a splash
|
||||
file is loaded.
|
||||
+
|
||||
+What: /sys/devices/platform/bootsplash.0/drop_splash
|
||||
+Date: Oct 2017
|
||||
+KernelVersion: 4.14
|
||||
+Contact: Max Staudt <mstaudt@suse.de>
|
||||
+Description:
|
||||
+ Can only be set.
|
||||
+
|
||||
+ Any value written will cause the current splash theme file
|
||||
+ to be unloaded and the text console to be redrawn.
|
||||
+
|
||||
+What: /sys/devices/platform/bootsplash.0/load_file
|
||||
+Date: Oct 2017
|
||||
+KernelVersion: 4.14
|
||||
+Contact: Max Staudt <mstaudt@suse.de>
|
||||
+Description:
|
||||
+ Can only be set.
|
||||
+
|
||||
+ Any value written will cause the splash to be disabled and
|
||||
+ internal memory structures to be freed.
|
||||
+
|
||||
+ A firmware path written will cause a new theme file to be
|
||||
+ loaded and the current bootsplash to be replaced.
|
||||
+ The current enabled/disabled status is not touched.
|
||||
+ If the splash is already active, it will be redrawn.
|
||||
+
|
||||
+ The path has to be a path in /lib/firmware since
|
||||
+ request_firmware() is used to fetch the data.
|
||||
+
|
||||
+ When setting the splash from the shell, echo -n has to be
|
||||
+ used as any trailing '\n' newline will be interpreted as
|
||||
+ part of the path.
|
||||
diff --git a/Documentation/bootsplash.rst b/Documentation/bootsplash.rst
|
||||
index 611f0c558925..b35aba5093e8 100644
|
||||
--- a/Documentation/bootsplash.rst
|
||||
+++ b/Documentation/bootsplash.rst
|
||||
@@ -67,6 +67,14 @@ sysfs run-time configuration
|
||||
a splash theme file is also loaded.
|
||||
|
||||
|
||||
+``/sys/devices/platform/bootsplash.0/drop_splash``
|
||||
+ Unload splash data and free memory.
|
||||
+
|
||||
+``/sys/devices/platform/bootsplash.0/load_file``
|
||||
+ Load a splash file from ``/lib/firmware/``.
|
||||
+ Note that trailing newlines will be interpreted as part of the file name.
|
||||
+
|
||||
+
|
||||
|
||||
Kconfig
|
||||
=======
|
||||
diff --git a/drivers/video/fbdev/core/bootsplash.c b/drivers/video/fbdev/core/bootsplash.c
|
||||
index 13fcaabbc2ca..16cb0493629d 100644
|
||||
--- a/drivers/video/fbdev/core/bootsplash.c
|
||||
+++ b/drivers/video/fbdev/core/bootsplash.c
|
||||
@@ -251,11 +251,65 @@ static ssize_t splash_store_enabled(struct device *device,
|
||||
return count;
|
||||
}
|
||||
|
||||
+static ssize_t splash_store_drop_splash(struct device *device,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ struct splash_file_priv *fp;
|
||||
+
|
||||
+ if (!buf || !count || !splash_state.file)
|
||||
+ return count;
|
||||
+
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ fp = splash_state.file;
|
||||
+ splash_state.file = NULL;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+
|
||||
+ /* Redraw the text console */
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ bootsplash_free_file(fp);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+static ssize_t splash_store_load_file(struct device *device,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t count)
|
||||
+{
|
||||
+ struct splash_file_priv *fp, *fp_old;
|
||||
+
|
||||
+ if (!count)
|
||||
+ return 0;
|
||||
+
|
||||
+ fp = bootsplash_load_firmware(&splash_state.splash_device->dev,
|
||||
+ buf);
|
||||
+
|
||||
+ if (!fp)
|
||||
+ return -ENXIO;
|
||||
+
|
||||
+ mutex_lock(&splash_state.data_lock);
|
||||
+ fp_old = splash_state.file;
|
||||
+ splash_state.splash_fb = NULL;
|
||||
+ splash_state.file = fp;
|
||||
+ mutex_unlock(&splash_state.data_lock);
|
||||
+
|
||||
+ /* Update the splash or text console */
|
||||
+ schedule_work(&splash_state.work_redraw_vc);
|
||||
+
|
||||
+ bootsplash_free_file(fp_old);
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
static DEVICE_ATTR(enabled, 0644, splash_show_enabled, splash_store_enabled);
|
||||
+static DEVICE_ATTR(drop_splash, 0200, NULL, splash_store_drop_splash);
|
||||
+static DEVICE_ATTR(load_file, 0200, NULL, splash_store_load_file);
|
||||
|
||||
|
||||
static struct attribute *splash_dev_attrs[] = {
|
||||
&dev_attr_enabled.attr,
|
||||
+ &dev_attr_drop_splash.attr,
|
||||
+ &dev_attr_load_file.attr,
|
||||
NULL
|
||||
};
|
||||
|
@ -1,511 +0,0 @@
|
||||
diff --git a/MAINTAINERS b/MAINTAINERS
|
||||
index 7ffac272434e..ddff07cd794c 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -2715,6 +2715,7 @@ F: drivers/video/fbdev/core/bootsplash*.*
|
||||
F: drivers/video/fbdev/core/dummycon.c
|
||||
F: include/linux/bootsplash.h
|
||||
F: include/uapi/linux/bootsplash_file.h
|
||||
+F: tools/bootsplash/*
|
||||
|
||||
BPF (Safe dynamic programs and tools)
|
||||
M: Alexei Starovoitov <ast@kernel.org>
|
||||
diff --git a/tools/bootsplash/.gitignore b/tools/bootsplash/.gitignore
|
||||
new file mode 100644
|
||||
index 000000000000..091b99a17567
|
||||
--- /dev/null
|
||||
+++ b/tools/bootsplash/.gitignore
|
||||
@@ -0,0 +1 @@
|
||||
+bootsplash-packer
|
||||
diff --git a/tools/bootsplash/Makefile b/tools/bootsplash/Makefile
|
||||
new file mode 100644
|
||||
index 000000000000..0ad8e8a84942
|
||||
--- /dev/null
|
||||
+++ b/tools/bootsplash/Makefile
|
||||
@@ -0,0 +1,9 @@
|
||||
+CC := $(CROSS_COMPILE)gcc
|
||||
+CFLAGS := -I../../usr/include
|
||||
+
|
||||
+PROGS := bootsplash-packer
|
||||
+
|
||||
+all: $(PROGS)
|
||||
+
|
||||
+clean:
|
||||
+ rm -fr $(PROGS)
|
||||
diff --git a/tools/bootsplash/bootsplash-packer.c b/tools/bootsplash/bootsplash-packer.c
|
||||
new file mode 100644
|
||||
index 000000000000..ffb6a8b69885
|
||||
--- /dev/null
|
||||
+++ b/tools/bootsplash/bootsplash-packer.c
|
||||
@@ -0,0 +1,471 @@
|
||||
+/*
|
||||
+ * Kernel based bootsplash.
|
||||
+ *
|
||||
+ * (Splash file packer tool)
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Max Staudt <mstaudt@suse.de>
|
||||
+ *
|
||||
+ * SPDX-License-Identifier: GPL-2.0
|
||||
+ */
|
||||
+
|
||||
+#include <endian.h>
|
||||
+#include <getopt.h>
|
||||
+#include <stdint.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <linux/bootsplash_file.h>
|
||||
+
|
||||
+
|
||||
+static void print_help(char *progname)
|
||||
+{
|
||||
+ printf("Usage: %s [OPTIONS] outfile\n", progname);
|
||||
+ printf("\n"
|
||||
+ "Options, executed in order given:\n"
|
||||
+ " -h, --help Print this help message\n"
|
||||
+ "\n"
|
||||
+ " --bg_red <u8> Background color (red part)\n"
|
||||
+ " --bg_green <u8> Background color (green part)\n"
|
||||
+ " --bg_blue <u8> Background color (blue part)\n"
|
||||
+ " --bg_reserved <u8> (do not use)\n"
|
||||
+ " --frame_ms <u16> Minimum milliseconds between animation steps\n"
|
||||
+ "\n"
|
||||
+ " --picture Start describing the next picture\n"
|
||||
+ " --pic_width <u16> Picture width in pixels\n"
|
||||
+ " --pic_height <u16> Picture height in pixels\n"
|
||||
+ " --pic_position <u8> Coarse picture placement:\n"
|
||||
+ " 0x00 - Top left\n"
|
||||
+ " 0x01 - Top\n"
|
||||
+ " 0x02 - Top right\n"
|
||||
+ " 0x03 - Right\n"
|
||||
+ " 0x04 - Bottom right\n"
|
||||
+ " 0x05 - Bottom\n"
|
||||
+ " 0x06 - Bottom left\n"
|
||||
+ " 0x07 - Left\n"
|
||||
+ "\n"
|
||||
+ " Flags:\n"
|
||||
+ " 0x10 - Calculate offset from corner towards center,\n"
|
||||
+ " rather than from center towards corner\n"
|
||||
+ " --pic_position_offset <u16> Distance from base position in pixels\n"
|
||||
+ " --pic_anim_type <u8> Animation type:\n"
|
||||
+ " 0 - None\n"
|
||||
+ " 1 - Forward loop\n"
|
||||
+ " --pic_anim_loop <u8> Loop point for animation\n"
|
||||
+ "\n"
|
||||
+ " --blob <filename> Include next data stream\n"
|
||||
+ " --blob_type <u16> Type of data\n"
|
||||
+ " --blob_picture_id <u8> Picture to associate this blob with, starting at 0\n"
|
||||
+ " (default: number of last --picture)\n"
|
||||
+ "\n");
|
||||
+ printf("This tool will write %s files.\n\n",
|
||||
+#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
+ "Big Endian (BE)");
|
||||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
+ "Little Endian (LE)");
|
||||
+#else
|
||||
+#error
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+
|
||||
+struct blob_entry {
|
||||
+ struct blob_entry *next;
|
||||
+
|
||||
+ char *fn;
|
||||
+
|
||||
+ struct splash_blob_header header;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static void dump_file_header(struct splash_file_header *h)
|
||||
+{
|
||||
+ printf(" --- File header ---\n");
|
||||
+ printf("\n");
|
||||
+ printf(" version: %5u\n", h->version);
|
||||
+ printf("\n");
|
||||
+ printf(" bg_red: %5u\n", h->bg_red);
|
||||
+ printf(" bg_green: %5u\n", h->bg_green);
|
||||
+ printf(" bg_blue: %5u\n", h->bg_blue);
|
||||
+ printf(" bg_reserved: %5u\n", h->bg_reserved);
|
||||
+ printf("\n");
|
||||
+ printf(" num_blobs: %5u\n", h->num_blobs);
|
||||
+ printf(" num_pics: %5u\n", h->num_pics);
|
||||
+ printf("\n");
|
||||
+ printf(" frame_ms: %5u\n", h->frame_ms);
|
||||
+ printf("\n");
|
||||
+}
|
||||
+
|
||||
+static void dump_pic_header(struct splash_pic_header *ph)
|
||||
+{
|
||||
+ printf(" --- Picture header ---\n");
|
||||
+ printf("\n");
|
||||
+ printf(" width: %5u\n", ph->width);
|
||||
+ printf(" height: %5u\n", ph->height);
|
||||
+ printf("\n");
|
||||
+ printf(" num_blobs: %5u\n", ph->num_blobs);
|
||||
+ printf("\n");
|
||||
+ printf(" position: %0x3x\n", ph->position);
|
||||
+ printf(" position_offset: %5u\n", ph->position_offset);
|
||||
+ printf("\n");
|
||||
+ printf(" anim_type: %5u\n", ph->anim_type);
|
||||
+ printf(" anim_loop: %5u\n", ph->anim_loop);
|
||||
+ printf("\n");
|
||||
+}
|
||||
+
|
||||
+static void dump_blob(struct blob_entry *b)
|
||||
+{
|
||||
+ printf(" --- Blob header ---\n");
|
||||
+ printf("\n");
|
||||
+ printf(" length: %7u\n", b->header.length);
|
||||
+ printf(" type: %7u\n", b->header.type);
|
||||
+ printf("\n");
|
||||
+ printf(" picture_id: %7u\n", b->header.picture_id);
|
||||
+ printf("\n");
|
||||
+}
|
||||
+
|
||||
+
|
||||
+#define OPT_MAX(var, max) \
|
||||
+ do { \
|
||||
+ if ((var) > max) { \
|
||||
+ fprintf(stderr, "--%s: Invalid value\n", \
|
||||
+ long_options[option_index].name); \
|
||||
+ break; \
|
||||
+ } \
|
||||
+ } while (0)
|
||||
+
|
||||
+static struct option long_options[] = {
|
||||
+ {"help", 0, 0, 'h'},
|
||||
+ {"bg_red", 1, 0, 10001},
|
||||
+ {"bg_green", 1, 0, 10002},
|
||||
+ {"bg_blue", 1, 0, 10003},
|
||||
+ {"bg_reserved", 1, 0, 10004},
|
||||
+ {"frame_ms", 1, 0, 10005},
|
||||
+ {"picture", 0, 0, 20000},
|
||||
+ {"pic_width", 1, 0, 20001},
|
||||
+ {"pic_height", 1, 0, 20002},
|
||||
+ {"pic_position", 1, 0, 20003},
|
||||
+ {"pic_position_offset", 1, 0, 20004},
|
||||
+ {"pic_anim_type", 1, 0, 20005},
|
||||
+ {"pic_anim_loop", 1, 0, 20006},
|
||||
+ {"blob", 1, 0, 30000},
|
||||
+ {"blob_type", 1, 0, 30001},
|
||||
+ {"blob_picture_id", 1, 0, 30002},
|
||||
+ {NULL, 0, NULL, 0}
|
||||
+};
|
||||
+
|
||||
+
|
||||
+int main(int argc, char **argv)
|
||||
+{
|
||||
+ FILE *of;
|
||||
+ char *ofn;
|
||||
+ int c;
|
||||
+ int option_index = 0;
|
||||
+
|
||||
+ unsigned long ul;
|
||||
+ struct splash_file_header fh = {};
|
||||
+ struct splash_pic_header ph[255];
|
||||
+ struct blob_entry *blob_first = NULL;
|
||||
+ struct blob_entry *blob_last = NULL;
|
||||
+ struct blob_entry *blob_cur = NULL;
|
||||
+
|
||||
+ if (argc < 2) {
|
||||
+ print_help(argv[0]);
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /* Parse and and execute user commands */
|
||||
+ while ((c = getopt_long(argc, argv, "h",
|
||||
+ long_options, &option_index)) != -1) {
|
||||
+ switch (c) {
|
||||
+ case 10001: /* bg_red */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ fh.bg_red = ul;
|
||||
+ break;
|
||||
+ case 10002: /* bg_green */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ fh.bg_green = ul;
|
||||
+ break;
|
||||
+ case 10003: /* bg_blue */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ fh.bg_blue = ul;
|
||||
+ break;
|
||||
+ case 10004: /* bg_reserved */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ fh.bg_reserved = ul;
|
||||
+ break;
|
||||
+ case 10005: /* frame_ms */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 65535);
|
||||
+ fh.frame_ms = ul;
|
||||
+ break;
|
||||
+
|
||||
+
|
||||
+ case 20000: /* picture */
|
||||
+ if (fh.num_pics >= 255) {
|
||||
+ fprintf(stderr, "--%s: Picture array full\n",
|
||||
+ long_options[option_index].name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ fh.num_pics++;
|
||||
+ break;
|
||||
+
|
||||
+ case 20001: /* pic_width */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 65535);
|
||||
+ ph[fh.num_pics - 1].width = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 20002: /* pic_height */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 65535);
|
||||
+ ph[fh.num_pics - 1].height = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 20003: /* pic_position */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ ph[fh.num_pics - 1].position = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 20004: /* pic_position_offset */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ ph[fh.num_pics - 1].position_offset = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 20005: /* pic_anim_type */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ ph[fh.num_pics - 1].anim_type = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 20006: /* pic_anim_loop */
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ ph[fh.num_pics - 1].anim_loop = ul;
|
||||
+ break;
|
||||
+
|
||||
+
|
||||
+ case 30000: /* blob */
|
||||
+ if (fh.num_blobs >= 65535) {
|
||||
+ fprintf(stderr, "--%s: Blob array full\n",
|
||||
+ long_options[option_index].name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ blob_cur = calloc(1, sizeof(struct blob_entry));
|
||||
+ if (!blob_cur) {
|
||||
+ fprintf(stderr, "--%s: Out of memory\n",
|
||||
+ long_options[option_index].name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ blob_cur->fn = optarg;
|
||||
+ if (fh.num_pics)
|
||||
+ blob_cur->header.picture_id = fh.num_pics - 1;
|
||||
+
|
||||
+ if (!blob_first)
|
||||
+ blob_first = blob_cur;
|
||||
+ if (blob_last)
|
||||
+ blob_last->next = blob_cur;
|
||||
+ blob_last = blob_cur;
|
||||
+ fh.num_blobs++;
|
||||
+ break;
|
||||
+
|
||||
+ case 30001: /* blob_type */
|
||||
+ if (!blob_cur) {
|
||||
+ fprintf(stderr, "--%s: No blob selected\n",
|
||||
+ long_options[option_index].name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ blob_cur->header.type = ul;
|
||||
+ break;
|
||||
+
|
||||
+ case 30002: /* blob_picture_id */
|
||||
+ if (!blob_cur) {
|
||||
+ fprintf(stderr, "--%s: No blob selected\n",
|
||||
+ long_options[option_index].name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ ul = strtoul(optarg, NULL, 0);
|
||||
+ OPT_MAX(ul, 255);
|
||||
+ blob_cur->header.picture_id = ul;
|
||||
+ break;
|
||||
+
|
||||
+
|
||||
+
|
||||
+ case 'h':
|
||||
+ case '?':
|
||||
+ default:
|
||||
+ print_help(argv[0]);
|
||||
+ goto EXIT;
|
||||
+ } /* switch (c) */
|
||||
+ } /* while ((c = getopt_long(...)) != -1) */
|
||||
+
|
||||
+ /* Consume and drop lone arguments */
|
||||
+ while (optind < argc) {
|
||||
+ ofn = argv[optind];
|
||||
+ optind++;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /* Read file lengths */
|
||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
|
||||
+ FILE *f;
|
||||
+ long pos;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!blob_cur->fn)
|
||||
+ continue;
|
||||
+
|
||||
+ f = fopen(blob_cur->fn, "rb");
|
||||
+ if (!f)
|
||||
+ goto ERR_FILE_LEN;
|
||||
+
|
||||
+ if (fseek(f, 0, SEEK_END))
|
||||
+ goto ERR_FILE_LEN;
|
||||
+
|
||||
+ pos = ftell(f);
|
||||
+ if (pos < 0 || pos > (1 << 30))
|
||||
+ goto ERR_FILE_LEN;
|
||||
+
|
||||
+ blob_cur->header.length = pos;
|
||||
+
|
||||
+ fclose(f);
|
||||
+ continue;
|
||||
+
|
||||
+ERR_FILE_LEN:
|
||||
+ fprintf(stderr, "Error getting file length (or too long): %s\n",
|
||||
+ blob_cur->fn);
|
||||
+ if (f)
|
||||
+ fclose(f);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /* Set magic headers */
|
||||
+#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_BE, 16);
|
||||
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
+ memcpy(&fh.id[0], BOOTSPLASH_MAGIC_LE, 16);
|
||||
+#else
|
||||
+#error
|
||||
+#endif
|
||||
+ fh.version = BOOTSPLASH_VERSION;
|
||||
+
|
||||
+ /* Set blob counts */
|
||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next) {
|
||||
+ if (blob_cur->header.picture_id < fh.num_pics)
|
||||
+ ph[blob_cur->header.picture_id].num_blobs++;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /* Dump structs */
|
||||
+ dump_file_header(&fh);
|
||||
+
|
||||
+ for (ul = 0; ul < fh.num_pics; ul++)
|
||||
+ dump_pic_header(&ph[ul]);
|
||||
+
|
||||
+ for (blob_cur = blob_first; blob_cur; blob_cur = blob_cur->next)
|
||||
+ dump_blob(blob_cur);
|
||||
+
|
||||
+
|
||||
+ /* Write to file */
|
||||
+ printf("Writing splash to file: %s\n", ofn);
|
||||
+ of = fopen(ofn, "wb");
|
||||
+ if (!of)
|
||||
+ goto ERR_WRITING;
|
||||
+
|
||||
+ if (fwrite(&fh, sizeof(struct splash_file_header), 1, of) != 1)
|
||||
+ goto ERR_WRITING;
|
||||
+
|
||||
+ for (ul = 0; ul < fh.num_pics; ul++) {
|
||||
+ if (fwrite(&ph[ul], sizeof(struct splash_pic_header), 1, of)
|
||||
+ != 1)
|
||||
+ goto ERR_WRITING;
|
||||
+ }
|
||||
+
|
||||
+ blob_cur = blob_first;
|
||||
+ while (blob_cur) {
|
||||
+ struct blob_entry *blob_old = blob_cur;
|
||||
+ FILE *f;
|
||||
+ char *buf[256];
|
||||
+ uint32_t left;
|
||||
+
|
||||
+ if (fwrite(&blob_cur->header,
|
||||
+ sizeof(struct splash_blob_header), 1, of) != 1)
|
||||
+ goto ERR_WRITING;
|
||||
+
|
||||
+ if (!blob_cur->header.length || !blob_cur->fn)
|
||||
+ continue;
|
||||
+
|
||||
+ f = fopen(blob_cur->fn, "rb");
|
||||
+ if (!f)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+
|
||||
+ left = blob_cur->header.length;
|
||||
+ while (left >= sizeof(buf)) {
|
||||
+ if (fread(buf, sizeof(buf), 1, f) != 1)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+ if (fwrite(buf, sizeof(buf), 1, of) != 1)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+ left -= sizeof(buf);
|
||||
+ }
|
||||
+ if (left) {
|
||||
+ if (fread(buf, left, 1, f) != 1)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+ if (fwrite(buf, left, 1, of) != 1)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+ }
|
||||
+
|
||||
+ /* Pad data stream to 16 bytes */
|
||||
+ if (left % 16) {
|
||||
+ if (fwrite("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
+ 16 - (left % 16), 1, of) != 1)
|
||||
+ goto ERR_FILE_COPY;
|
||||
+ }
|
||||
+
|
||||
+ fclose(f);
|
||||
+ blob_cur = blob_cur->next;
|
||||
+ free(blob_old);
|
||||
+ continue;
|
||||
+
|
||||
+ERR_FILE_COPY:
|
||||
+ if (f)
|
||||
+ fclose(f);
|
||||
+ goto ERR_WRITING;
|
||||
+ }
|
||||
+
|
||||
+ fclose(of);
|
||||
+
|
||||
+EXIT:
|
||||
+ return EXIT_SUCCESS;
|
||||
+
|
||||
+
|
||||
+ERR_WRITING:
|
||||
+ fprintf(stderr, "Error writing splash.\n");
|
||||
+ fprintf(stderr, "The output file is probably corrupt.\n");
|
||||
+ if (of)
|
||||
+ fclose(of);
|
||||
+
|
||||
+ while (blob_cur) {
|
||||
+ struct blob_entry *blob_old = blob_cur;
|
||||
+
|
||||
+ blob_cur = blob_cur->next;
|
||||
+ free(blob_old);
|
||||
+ }
|
||||
+
|
||||
+ return EXIT_FAILURE;
|
||||
+}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
||||
[Trigger]
|
||||
Type = File
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Operation = Remove
|
||||
Target = usr/lib/modules/%KERNVER%/*
|
||||
Target = usr/lib/modules/%EXTRAMODULES%/*
|
||||
|
||||
[Action]
|
||||
Description = Updating %PKGBASE% module dependencies...
|
||||
When = PostTransaction
|
||||
Exec = /usr/bin/depmod %KERNVER%
|
@ -1,11 +0,0 @@
|
||||
[Trigger]
|
||||
Type = File
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Target = boot/Image
|
||||
Target = usr/lib/initcpio/*
|
||||
|
||||
[Action]
|
||||
Description = Updating %PKGBASE% initcpios...
|
||||
When = PostTransaction
|
||||
Exec = /usr/bin/mkinitcpio -p %PKGBASE%
|
@ -1,330 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-21.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT,
|
||||
USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 3BECEC433E0
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id E48DB64F1D
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:05 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233163AbhCMH6d (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:33 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58938 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S230309AbhCMH55 (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:57:57 -0500
|
||||
Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25364C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:57 -0800 (PST)
|
||||
Received: by mail-qk1-x74a.google.com with SMTP id k188so1766042qkb.5
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:57 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:message-id:mime-version:subject:from:to:cc;
|
||||
bh=Dl/3fLOB0H+oajTIzqKaDQePlH9N08uWOrKgpspO4TI=;
|
||||
b=ZDlp8kO1cOzH9TKK391ns60MA5XH6wAt4WlC5cRspVrndQuLOdzpe4WuBER+H/7iF2
|
||||
P/jJN5bw/W10rtSgEJl+3nFM9KliKjzDKLX1Wjo+FdVZj7lWam1qWgkQTlezZ+NtB7MK
|
||||
cT+C7m++Ac2yj63uufwG9IIyPjtCqwGGHd6caaZjsFdwrZIYl6mprawhmN0ajnA+KxLu
|
||||
3msx/zJkbVaZ75VF4EavCd4hAKjuHACTjU5DSIC+hq9i3Y5TuQGinRu50cx5wXXQqKu+
|
||||
TLyLtiLkTbZaVeLhF0uQooG8E4w+JXFmnfMxWOPsekXQyWZHebj5hpUPJ1nW39iQnMBt
|
||||
NShw==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc;
|
||||
bh=Dl/3fLOB0H+oajTIzqKaDQePlH9N08uWOrKgpspO4TI=;
|
||||
b=XOeOFYm39AC6u/tzgFN40WA+JyClAjJZL1vfB4B2WAz2bh8R5boQeyY2Px52/PXMqe
|
||||
PCZUSDqqa3qe2AL+XMFxSKay7L4rvvcPP294PgvjMTHIci5V4Nvhb2gooGAFYMoxkgvH
|
||||
lEixBlTS6nGyJ8IubphUQVdIAQN9EaHViPwha6EQb3TvAyPjae5NDLVjv32BjQLi8CGw
|
||||
OTubWcbqjEu/b5lo0MSHi/e6RCI3rcUJRFagT567WMEKCRXl9L9lKS2Y/hxoG2vx6f7E
|
||||
NTzYk8hh52IHO/hBULiYGwss1WApIAFZmg6gkNZJQhw3Z7ZYCxHz7oMXAJCzFeOBikcZ
|
||||
lJnw==
|
||||
X-Gm-Message-State: AOAM5315xRkAW2HlZY5TGBhlW7nW/go+xoCYXD97M7G+xWGL5D5tgqcK
|
||||
MXUwE4z8bQg+QCpnSwxROcufEldhmTU=
|
||||
X-Google-Smtp-Source: ABdhPJyxefk+CsNOhJRg0zohX7wmgO41UdqyprhNKHQCCmk9ImMeIO+UNC1eONE3N7hnVkFPu9qRD/MnUEM=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a0c:fc06:: with SMTP id z6mr1801957qvo.25.1615622276103;
|
||||
Fri, 12 Mar 2021 23:57:56 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:33 -0700
|
||||
Message-Id: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 00/14] Multigenerational LRU
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-1-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
TLDR
|
||||
====
|
||||
The current page reclaim is too expensive in terms of CPU usage and
|
||||
often making poor choices about what to evict. We would like to offer
|
||||
a performant, versatile and straightforward augment.
|
||||
|
||||
Repo
|
||||
====
|
||||
git fetch https://linux-mm.googlesource.com/page-reclaim refs/changes/01/1101/1
|
||||
|
||||
Gerrit https://linux-mm-review.googlesource.com/c/page-reclaim/+/1101
|
||||
|
||||
Background
|
||||
==========
|
||||
DRAM is a major factor in total cost of ownership, and improving
|
||||
memory overcommit brings a high return on investment. Over the past
|
||||
decade of research and experimentation in memory overcommit, we
|
||||
observed a distinct trend across millions of servers and clients: the
|
||||
size of page cache has been decreasing because of the growing
|
||||
popularity of cloud storage. Nowadays anon pages account for more than
|
||||
90% of our memory consumption and page cache contains mostly
|
||||
executable pages.
|
||||
|
||||
Problems
|
||||
========
|
||||
Notion of the active/inactive
|
||||
-----------------------------
|
||||
For servers equipped with hundreds of gigabytes of memory, the
|
||||
granularity of the active/inactive is too coarse to be useful for job
|
||||
scheduling. And false active/inactive rates are relatively high. In
|
||||
addition, scans of largely varying numbers of pages are unpredictable
|
||||
because inactive_is_low() is based on magic numbers.
|
||||
|
||||
For phones and laptops, the eviction is biased toward file pages
|
||||
because the selection has to resort to heuristics as direct
|
||||
comparisons between anon and file types are infeasible. On Android and
|
||||
Chrome OS, executable pages are frequently evicted despite the fact
|
||||
that there are many less recently used anon pages. This causes "janks"
|
||||
(slow UI rendering) and negatively impacts user experience.
|
||||
|
||||
For systems with multiple nodes and/or memcgs, it is impossible to
|
||||
compare lruvecs based on the notion of the active/inactive.
|
||||
|
||||
Incremental scans via the rmap
|
||||
------------------------------
|
||||
Each incremental scan picks up at where the last scan left off and
|
||||
stops after it has found a handful of unreferenced pages. For most of
|
||||
the systems running cloud workloads, incremental scans lose the
|
||||
advantage under sustained memory pressure due to high ratios of the
|
||||
number of scanned pages to the number of reclaimed pages. In our case,
|
||||
the average ratio of pgscan to pgsteal is about 7.
|
||||
|
||||
On top of that, the rmap has poor memory locality due to its complex
|
||||
data structures. The combined effects typically result in a high
|
||||
amount of CPU usage in the reclaim path. For example, with zram, a
|
||||
typical kswapd profile on v5.11 looks like:
|
||||
31.03% page_vma_mapped_walk
|
||||
25.59% lzo1x_1_do_compress
|
||||
4.63% do_raw_spin_lock
|
||||
3.89% vma_interval_tree_iter_next
|
||||
3.33% vma_interval_tree_subtree_search
|
||||
|
||||
And with real swap, it looks like:
|
||||
45.16% page_vma_mapped_walk
|
||||
7.61% do_raw_spin_lock
|
||||
5.69% vma_interval_tree_iter_next
|
||||
4.91% vma_interval_tree_subtree_search
|
||||
3.71% page_referenced_one
|
||||
|
||||
Solutions
|
||||
=========
|
||||
Notion of generation numbers
|
||||
----------------------------
|
||||
The notion of generation numbers introduces a quantitative approach to
|
||||
memory overcommit. A larger number of pages can be spread out across
|
||||
configurable generations, and thus they have relatively low false
|
||||
active/inactive rates. Each generation includes all pages that have
|
||||
been referenced since the last generation.
|
||||
|
||||
Given an lruvec, scans and the selections between anon and file types
|
||||
are all based on generation numbers, which are simple and yet
|
||||
effective. For different lruvecs, comparisons are still possible based
|
||||
on birth times of generations.
|
||||
|
||||
Differential scans via page tables
|
||||
----------------------------------
|
||||
Each differential scan discovers all pages that have been referenced
|
||||
since the last scan. Specifically, it walks the mm_struct list
|
||||
associated with an lruvec to scan page tables of processes that have
|
||||
been scheduled since the last scan. The cost of each differential scan
|
||||
is roughly proportional to the number of referenced pages it
|
||||
discovers. Unless address spaces are extremely sparse, page tables
|
||||
usually have better memory locality than the rmap. The end result is
|
||||
generally a significant reduction in CPU usage, for most of the
|
||||
systems running cloud workloads.
|
||||
|
||||
On Chrome OS, our real-world benchmark that browses popular websites
|
||||
in multiple tabs demonstrates 51% less CPU usage from kswapd and 52%
|
||||
(full) less PSI on v5.11. And kswapd profile looks like:
|
||||
49.36% lzo1x_1_do_compress
|
||||
4.54% page_vma_mapped_walk
|
||||
4.45% memset_erms
|
||||
3.47% walk_pte_range
|
||||
2.88% zram_bvec_rw
|
||||
|
||||
In addition, direct reclaim latency is reduced by 22% at 99th
|
||||
percentile and the number of refaults is reduced 7%. These metrics are
|
||||
important to phones and laptops as they are correlated to user
|
||||
experience.
|
||||
|
||||
Workflow
|
||||
========
|
||||
Evictable pages are divided into multiple generations for each lruvec.
|
||||
The youngest generation number is stored in lruvec->evictable.max_seq
|
||||
for both anon and file types as they are aged on an equal footing. The
|
||||
oldest generation numbers are stored in lruvec->evictable.min_seq[2]
|
||||
separately for anon and file types as clean file pages can be evicted
|
||||
regardless of may_swap or may_writepage. Generation numbers are
|
||||
truncated into ilog2(MAX_NR_GENS)+1 bits in order to fit into
|
||||
page->flags. The sliding window technique is used to prevent truncated
|
||||
generation numbers from overlapping. Each truncated generation number
|
||||
is an index to
|
||||
lruvec->evictable.lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES].
|
||||
Evictable pages are added to the per-zone lists indexed by max_seq or
|
||||
min_seq[2] (modulo MAX_NR_GENS), depending on whether they are being
|
||||
faulted in or read ahead. The workflow comprises two conceptually
|
||||
independent functions: the aging and the eviction.
|
||||
|
||||
Aging
|
||||
-----
|
||||
The aging produces young generations. Given an lruvec, the aging scans
|
||||
page tables for referenced pages of this lruvec. Upon finding one, the
|
||||
aging updates its generation number to max_seq. After each round of
|
||||
scan, the aging increments max_seq. The aging maintains either a
|
||||
system-wide mm_struct list or per-memcg mm_struct lists and tracks
|
||||
whether an mm_struct is being used on any CPUs or has been used since
|
||||
the last scan. Multiple threads can concurrently work on the same
|
||||
mm_struct list, and each of them will be given a different mm_struct
|
||||
belonging to a process that has been scheduled since the last scan.
|
||||
|
||||
Eviction
|
||||
--------
|
||||
The eviction consumes old generations. Given an lruvec, the eviction
|
||||
scans the pages on the per-zone lists indexed by either of min_seq[2].
|
||||
It selects a type according to the values of min_seq[2] and
|
||||
swappiness. During a scan, the eviction either sorts or isolates a
|
||||
page, depending on whether the aging has updated its generation
|
||||
number. When it finds all the per-zone lists are empty, the eviction
|
||||
increments min_seq[2] indexed by this selected type. The eviction
|
||||
triggers the aging when both of min_seq[2] reaches max_seq-1, assuming
|
||||
both anon and file types are reclaimable.
|
||||
|
||||
Use cases
|
||||
=========
|
||||
On Android, our most advanced simulation that generates memory
|
||||
pressure from realistic user behavior shows 18% fewer low-memory
|
||||
kills, which in turn reduces cold starts by 16%.
|
||||
|
||||
On Borg, a similar approach enables us to identify jobs that
|
||||
underutilize their memory and downsize them considerably without
|
||||
compromising any of our service level indicators.
|
||||
|
||||
On Chrome OS, our field telemetry reports 96% fewer low-memory tab
|
||||
discards and 59% fewer OOM kills from fully-utilized devices and no UX
|
||||
regressions from underutilized devices.
|
||||
|
||||
For other use cases include working set estimation, proactive reclaim,
|
||||
far memory tiering and NUMA-aware job scheduling, please refer to the
|
||||
documentation included in this series and the following references.
|
||||
|
||||
References
|
||||
==========
|
||||
1. Long-term SLOs for reclaimed cloud computing resources
|
||||
https://research.google/pubs/pub43017/
|
||||
2. Profiling a warehouse-scale computer
|
||||
https://research.google/pubs/pub44271/
|
||||
3. Evaluation of NUMA-Aware Scheduling in Warehouse-Scale Clusters
|
||||
https://research.google/pubs/pub48329/
|
||||
4. Software-defined far memory in warehouse-scale computers
|
||||
https://research.google/pubs/pub48551/
|
||||
5. Borg: the Next Generation
|
||||
https://research.google/pubs/pub49065/
|
||||
|
||||
Yu Zhao (14):
|
||||
include/linux/memcontrol.h: do not warn in page_memcg_rcu() if
|
||||
!CONFIG_MEMCG
|
||||
include/linux/nodemask.h: define next_memory_node() if !CONFIG_NUMA
|
||||
include/linux/huge_mm.h: define is_huge_zero_pmd() if
|
||||
!CONFIG_TRANSPARENT_HUGEPAGE
|
||||
include/linux/cgroup.h: export cgroup_mutex
|
||||
mm/swap.c: export activate_page()
|
||||
mm, x86: support the access bit on non-leaf PMD entries
|
||||
mm/pagewalk.c: add pud_entry_post() for post-order traversals
|
||||
mm/vmscan.c: refactor shrink_node()
|
||||
mm: multigenerational lru: mm_struct list
|
||||
mm: multigenerational lru: core
|
||||
mm: multigenerational lru: page activation
|
||||
mm: multigenerational lru: user space interface
|
||||
mm: multigenerational lru: Kconfig
|
||||
mm: multigenerational lru: documentation
|
||||
|
||||
Documentation/vm/index.rst | 1 +
|
||||
Documentation/vm/multigen_lru.rst | 210 +++
|
||||
arch/Kconfig | 8 +
|
||||
arch/x86/Kconfig | 1 +
|
||||
arch/x86/include/asm/pgtable.h | 2 +-
|
||||
arch/x86/mm/pgtable.c | 5 +-
|
||||
fs/exec.c | 2 +
|
||||
fs/proc/task_mmu.c | 3 +-
|
||||
include/linux/cgroup.h | 15 +-
|
||||
include/linux/huge_mm.h | 5 +
|
||||
include/linux/memcontrol.h | 5 +-
|
||||
include/linux/mm.h | 1 +
|
||||
include/linux/mm_inline.h | 246 ++++
|
||||
include/linux/mm_types.h | 135 ++
|
||||
include/linux/mmzone.h | 62 +-
|
||||
include/linux/nodemask.h | 1 +
|
||||
include/linux/page-flags-layout.h | 20 +-
|
||||
include/linux/pagewalk.h | 4 +
|
||||
include/linux/pgtable.h | 4 +-
|
||||
include/linux/swap.h | 5 +-
|
||||
kernel/events/uprobes.c | 2 +-
|
||||
kernel/exit.c | 1 +
|
||||
kernel/fork.c | 10 +
|
||||
kernel/kthread.c | 1 +
|
||||
kernel/sched/core.c | 2 +
|
||||
mm/Kconfig | 29 +
|
||||
mm/huge_memory.c | 5 +-
|
||||
mm/khugepaged.c | 2 +-
|
||||
mm/memcontrol.c | 28 +
|
||||
mm/memory.c | 14 +-
|
||||
mm/migrate.c | 2 +-
|
||||
mm/mm_init.c | 13 +-
|
||||
mm/mmzone.c | 2 +
|
||||
mm/pagewalk.c | 5 +
|
||||
mm/rmap.c | 6 +
|
||||
mm/swap.c | 58 +-
|
||||
mm/swapfile.c | 6 +-
|
||||
mm/userfaultfd.c | 2 +-
|
||||
mm/vmscan.c | 2091 +++++++++++++++++++++++++++--
|
||||
39 files changed, 2870 insertions(+), 144 deletions(-)
|
||||
create mode 100644 Documentation/vm/multigen_lru.rst
|
||||
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,129 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 42B16C433DB
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 11CED64ECE
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233237AbhCMH6e (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:34 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58944 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S230349AbhCMH56 (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:57:58 -0500
|
||||
Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7B7EAC061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:58 -0800 (PST)
|
||||
Received: by mail-yb1-xb49.google.com with SMTP id d8so32058455ybs.11
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:58 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=CiMQJrfmhcT/Xw28mTP3VlU5SRPV8bRsC232LNJk7tU=;
|
||||
b=U+bvs2P4aWZrWqfRwrXFunM/l5sWGKqRdiGQFJBSXwSH+vfw4kB3WjkPPQpoUgHwwx
|
||||
+4KITrOtke32as1JFmSOW/QJ8GYL6J2CyqtNZysfNDnr4dUu1eafFf0OU/BN2PlR6TZw
|
||||
u/bOTirXcAreUn8QrcDvxRKbQwugJdk2JWl2TqDc7KAmb0AodFb/pAgQnWip2QOqWta3
|
||||
5ohqe66l196K6u9PNyDcJqEzz4CuJBMkGEAupVYjzX/HNuFZ1kLz2lz2FxSR38TqyX8I
|
||||
aWFk3lMppRkLaWpnC4nC3SQhZcJq9YOxrujTA4BSnsEwscy7qJzgt8w9xEMiwzmAoN1g
|
||||
Bm1Q==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=CiMQJrfmhcT/Xw28mTP3VlU5SRPV8bRsC232LNJk7tU=;
|
||||
b=Qi2PdmMPthJWQMXSQ05Fb8upxFWwOHNAFsy8LixbQ0QGPKWVlwBzQDYwPCpG05WFP8
|
||||
cYIfPhq3nv9++78Y1Pw7Q8oiGEv7KJ0j/sHIaRZGlWZdHWwciPpKdT9M4JVXYhn4NxhF
|
||||
6YrPBHSTOTN7v9fuCOcPqKSOKTBYMF/eETj9XoeqtvetJVZ1i3Dqxu4TawWOlymnTTkh
|
||||
9IQRnTz2ffdTJdBCH6iTA0UfrEDWDnESubVvzuRfmLvCt3b427gwHWXaK/i7F/60+65O
|
||||
8gzoqIJ9gqwTfdGB3vB6HXtbmWosQ39Zy7gnpTpf0CB7afg1Gnx/4Y26GMLjtLkzeviQ
|
||||
6K7w==
|
||||
X-Gm-Message-State: AOAM531kmbzmJE5p9rtDGXbRHYBSsGjPyFJxoBPqsQzAq6DHfRzY/is2
|
||||
Lgnmsa+bse/YLa5M+1JDlGqGCZxMntQ=
|
||||
X-Google-Smtp-Source: ABdhPJxUTV3MKesWpiHjP1OfC2lc1y93+U3j9zDFMK1igY41oF3Fyu2enmEiwR5c1z6fz0Ykw1sgyEJETNk=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a25:dfd1:: with SMTP id w200mr24182984ybg.362.1615622277472;
|
||||
Fri, 12 Mar 2021 23:57:57 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:34 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-2-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 01/14] include/linux/memcontrol.h: do not warn in
|
||||
page_memcg_rcu() if !CONFIG_MEMCG
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-2-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
We want to make sure the rcu lock is held while using
|
||||
page_memcg_rcu(). But having a WARN_ON_ONCE() in page_memcg_rcu() when
|
||||
!CONFIG_MEMCG is superfluous because of the following legit use case:
|
||||
|
||||
memcg = lock_page_memcg(page1)
|
||||
(rcu_read_lock() if CONFIG_MEMCG=y)
|
||||
|
||||
do something to page1
|
||||
|
||||
if (page_memcg_rcu(page2) == memcg)
|
||||
do something to page2 too as it cannot be migrated away from the
|
||||
memcg either.
|
||||
|
||||
unlock_page_memcg(page1)
|
||||
(rcu_read_unlock() if CONFIG_MEMCG=y)
|
||||
|
||||
This patch removes the WARN_ON_ONCE() from page_memcg_rcu() for the
|
||||
!CONFIG_MEMCG case.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/memcontrol.h | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
|
||||
index e6dc793d587d..f325aeb4b4e8 100644
|
||||
--- a/include/linux/memcontrol.h
|
||||
+++ b/include/linux/memcontrol.h
|
||||
@@ -1079,7 +1079,6 @@ static inline struct mem_cgroup *page_memcg(struct page *page)
|
||||
|
||||
static inline struct mem_cgroup *page_memcg_rcu(struct page *page)
|
||||
{
|
||||
- WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,113 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 7CAADC433E9
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 4C9E564ECE
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233343AbhCMH6f (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:35 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58950 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S231723AbhCMH57 (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:57:59 -0500
|
||||
Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B79D0C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:59 -0800 (PST)
|
||||
Received: by mail-qk1-x74a.google.com with SMTP id k68so19900263qke.2
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:57:59 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=8JNiZUfBDRjXaPYBpQeMTXnhFbhlF+xtdVruxqSh3cA=;
|
||||
b=IxvaJGLX6pUI5R+Y+pYVqc8/0gQYUuErDfxr3dMFZudBUHTyTTMgRdE0XBcCau7R3l
|
||||
WVURZXlPOHDzjeCRAmjp2GkNmw3M99Sx/iwvc+iSD8ohg8gx7Cj3TzTxPdzUCsghnFFL
|
||||
Hv+lIk4SezNfKgceCzGd/c+Rf6ueoDDPEzD62ZXkdDxk/uLmQc4GjBU0Knksz2+dLsVo
|
||||
b2U0CgK0WmdW2qIHy4OyEo2nBB4jmzDFCPxxlIobZYlIAsooUXen6yoe28K/2f1TgtI5
|
||||
p1/lftklJT4PvJibzbIlGo6vGha2wAL2lU0ks0AxI4l1lf/1Bf/PVsGVaXXW7+F/fJFj
|
||||
Y3HQ==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=8JNiZUfBDRjXaPYBpQeMTXnhFbhlF+xtdVruxqSh3cA=;
|
||||
b=gAD0lTpWpuRmUv2Dlufjuw7ZklBUzo8DSa0cxSlaWPJunVm1RpqFGuQ0dz/Q5SDxC8
|
||||
e2XkyRSyCbrJ2qPrJUA+p5trg9qCQq4i4twAOZW4+6JOmPcDhnjMZ5aZGSzfoiMIRsoT
|
||||
4EV2Q02mcFvf2IuUgWli5WndTXndhzHNpFWCsogvzS+JWqWb6aY+e+5tJWSfWH3kCiDw
|
||||
t8uRvv61lDKzNQeIpa/ZbY8MFF4olHkRwvO5FMf2xUfghMxRoosJSB3DdLIiwC8NEbpr
|
||||
g7dGskt+2tbLFnNCykjqc81I4A/sSyeBg95oUKs9PNAIBgIoAQlvqOizUcVccM9r97dk
|
||||
dPYA==
|
||||
X-Gm-Message-State: AOAM533j3NWtnjtXQODMvkwfUeiEAcpKyeqz3jm23oO6viFDFeKf35BJ
|
||||
zE9lWSBpsopJHLabXkGrebl2ktdd2BY=
|
||||
X-Google-Smtp-Source: ABdhPJwORNu5jWRG63mEkIrwerIFX+r6WsDRo4k6jBRlD+35Q3Ytikr16dVGNSyDCuR7br75GADeWLQhEY0=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:ad4:5ce8:: with SMTP id iv8mr1757086qvb.16.1615622278881;
|
||||
Fri, 12 Mar 2021 23:57:58 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:35 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-3-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 02/14] include/linux/nodemask.h: define next_memory_node()
|
||||
if !CONFIG_NUMA
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-3-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Currently next_memory_node only exists when CONFIG_NUMA=y. This patch
|
||||
defines the macro for the !CONFIG_NUMA case.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/nodemask.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
|
||||
index ac398e143c9a..89fe4e3592f9 100644
|
||||
--- a/include/linux/nodemask.h
|
||||
+++ b/include/linux/nodemask.h
|
||||
@@ -486,6 +486,7 @@ static inline int num_node_state(enum node_states state)
|
||||
#define first_online_node 0
|
||||
#define first_memory_node 0
|
||||
#define next_online_node(nid) (MAX_NUMNODES)
|
||||
+#define next_memory_node(nid) (MAX_NUMNODES)
|
||||
#define nr_node_ids 1U
|
||||
#define nr_online_nodes 1U
|
||||
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 97984C433E6
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 62DCA64F1E
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233389AbhCMH6g (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:36 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58956 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232023AbhCMH6B (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:01 -0500
|
||||
Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 055BEC061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:01 -0800 (PST)
|
||||
Received: by mail-qk1-x74a.google.com with SMTP id u5so19869532qkj.10
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:00 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=BUGHWaLOgbBXMks9MxevCFPE+HJdHu8WtN3Ad5BKa2E=;
|
||||
b=EmtSmNZcxIc0Qq98PvQLlh/Je74+I9pGiId+AoSzt2WN66X/7gqva2AkM1Z6ZrqWlC
|
||||
qMCo9fu+KgWIl13K9lL0hfZkSMTr33It30mFN/3/xwUcpWXiUy2ttup7BflThw89akrm
|
||||
ipCdNg7GP9J1lKGO0+Ae8TZbHboXPO6EU2DcK5O1kt2ZE3NOFthikv0X6/opyUBdeUKR
|
||||
Q3HhM/pgOA+vQ4UMR7hzNtEDZcmVDtrPgTwq9zDoYDV/KHqaCvxRPvrkCfwY3MbDN9Yc
|
||||
Dm0TaDfpoFKrj/syFqJ/83hwIk0G3OPLs6DbY/I2HkHJ6cbjakxVLFDyXybDitO9MyGA
|
||||
/tow==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=BUGHWaLOgbBXMks9MxevCFPE+HJdHu8WtN3Ad5BKa2E=;
|
||||
b=tk+Szu/MRdyl1iY0zpUHO4VtD8YBAHs5CFbud9sFWZl8OIpU011Pd59sKmQkChiEw7
|
||||
YEzG58xR4zAwc8CM8Vd7HuqKhhVUDIqumg0Ntx1KyfQ2QNYcbVSv8oAHuMLxAAembJau
|
||||
D5EsuQjvXjKjroV/zEhusebtXIHZULBN1x9MfQwyikGwihqLhzDwXeUHx2D7JFo7i40J
|
||||
3hvB0UCXdGNVF257C0gUQWS/r0tKshrTyX1i7tyAutY7viCISRQ6FP65DlTjV3PAmmsw
|
||||
VHxDK47EkcJAoat+x24kFd6i44dgww1DGsDCpvBZu8P/V1m2f4keblf2wZMFsVwDhZRU
|
||||
0b/g==
|
||||
X-Gm-Message-State: AOAM5314IBqaZ2bDNgLAPxQ3EGGAGDitVyFeUtt5HNFWNSHljmLCuPyl
|
||||
iPCluBY4dSP0ON55Ckf7BwK1bpQBiw8=
|
||||
X-Google-Smtp-Source: ABdhPJzJJ1SnzBtj3bVJq+tnpS8mvob3Iwgd7McsgFl/pDIRa/R9w7/nQuY0bxlcdhV2mXDJvzzuC77PvVA=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a05:6214:4b3:: with SMTP id
|
||||
w19mr1750690qvz.26.1615622280155; Fri, 12 Mar 2021 23:58:00 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:36 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-4-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 03/14] include/linux/huge_mm.h: define is_huge_zero_pmd()
|
||||
if !CONFIG_TRANSPARENT_HUGEPAGE
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-4-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Currently is_huge_zero_pmd() only exists when
|
||||
CONFIG_TRANSPARENT_HUGEPAGE=y. This patch defines the function for the
|
||||
!CONFIG_TRANSPARENT_HUGEPAGE case.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/huge_mm.h | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
|
||||
index ba973efcd369..0ba7b3f9029c 100644
|
||||
--- a/include/linux/huge_mm.h
|
||||
+++ b/include/linux/huge_mm.h
|
||||
@@ -443,6 +443,11 @@ static inline bool is_huge_zero_page(struct page *page)
|
||||
return false;
|
||||
}
|
||||
|
||||
+static inline bool is_huge_zero_pmd(pmd_t pmd)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static inline bool is_huge_zero_pud(pud_t pud)
|
||||
{
|
||||
return false;
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,140 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id A8DC7C43381
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 7FA3564F1D
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233409AbhCMH6i (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:38 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58964 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232230AbhCMH6C (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:02 -0500
|
||||
Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 562C3C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:02 -0800 (PST)
|
||||
Received: by mail-qk1-x74a.google.com with SMTP id d137so4579263qkb.18
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:02 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=aLRTkKE+4395hmMwkgIvoFPbmsRrSNB3cb7TyZ2ydVo=;
|
||||
b=RbyWeK4rUqhSF6l4+WOn4bz/6l7Kc8FPXxW3gI+7y8uPJAZ1QX8cf/I1Awt1gV/SbI
|
||||
bjnyW7mGxY1NMOZzzbS/+Pu/wZOk8PcdLyHQjU8FYS7MY3rlxWHPLiUeDkvVnQXqR/vU
|
||||
VjFNQgX24G3KsIyOvy72WKVvMUMe73K7lMeGcaq5JwzYtlJpwJmAq7im1mo7v1rCTUgA
|
||||
0mo4ifiQHDGxfCFwMiqlcmL9XCp3IrCMWE8XU4ROv4uXfZw0LtfhovB0FFVhgU4OaGPo
|
||||
9xkxh+e9HnpJUWha5GVEemFT2phEp+qmiZ0b0RvdNPBXFoxHBjwLSKOp/alc26idQnA2
|
||||
6ehw==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=aLRTkKE+4395hmMwkgIvoFPbmsRrSNB3cb7TyZ2ydVo=;
|
||||
b=sPWOPGHoVohb7G6EOihIswCUjaDOMsg/DvRB2ugPnziQk8PcjMml4kYe8yFsYiBamJ
|
||||
ZBRsKYaIxBbegmcuF2aq6FE8IRzx6eYh8i5L6RQ83/jPcS1VVViz30AEgGo2OR0qlRtK
|
||||
6e9I4lEcrR67MLWdkHooamn5SOvnTfgJcr7FGERX+0O/FzSxT56KcHTaEjHYnS68pxQM
|
||||
cryChrhdy5jpPx9+EiGLdZI95GTYYHE3/TXMlABP1Dv4YEWI93zhR/ePrlm0SjEioKWR
|
||||
PW1K3Blnn4t6EIlzyEcAxmVz7702MA3b1x1hM3iPT6B+pwdovapsNRL+JH3s67twnKUc
|
||||
qBWQ==
|
||||
X-Gm-Message-State: AOAM532W7wUq4pmKjtVvHSPslHZDT9pB3jR1xJmNsJD9ZqrBMl8E+xpH
|
||||
v9xzx/Rcs8diDMvgzLYOU4hfhWFObf4=
|
||||
X-Google-Smtp-Source: ABdhPJwU+Y5hioYI52CJyazw+FjQUFeKf1QbQJTSQIAKTuuIxfYVSs2ErBNlMhmNRx4/c6B7zv8sBwMBzxE=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:ad4:5c87:: with SMTP id o7mr1743197qvh.31.1615622281483;
|
||||
Fri, 12 Mar 2021 23:58:01 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:37 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-5-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 04/14] include/linux/cgroup.h: export cgroup_mutex
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-5-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Export cgroup_mutex so it can be used to synchronize with memcg
|
||||
allocations.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/cgroup.h | 15 ++++++++++++++-
|
||||
1 file changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
|
||||
index 4f2f79de083e..bd5744360cfa 100644
|
||||
--- a/include/linux/cgroup.h
|
||||
+++ b/include/linux/cgroup.h
|
||||
@@ -432,6 +432,18 @@ static inline void cgroup_put(struct cgroup *cgrp)
|
||||
css_put(&cgrp->self);
|
||||
}
|
||||
|
||||
+extern struct mutex cgroup_mutex;
|
||||
+
|
||||
+static inline void cgroup_lock(void)
|
||||
+{
|
||||
+ mutex_lock(&cgroup_mutex);
|
||||
+}
|
||||
+
|
||||
+static inline void cgroup_unlock(void)
|
||||
+{
|
||||
+ mutex_unlock(&cgroup_mutex);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* task_css_set_check - obtain a task's css_set with extra access conditions
|
||||
* @task: the task to obtain css_set for
|
||||
@@ -446,7 +458,6 @@ static inline void cgroup_put(struct cgroup *cgrp)
|
||||
* as locks used during the cgroup_subsys::attach() methods.
|
||||
*/
|
||||
#ifdef CONFIG_PROVE_RCU
|
||||
-extern struct mutex cgroup_mutex;
|
||||
extern spinlock_t css_set_lock;
|
||||
#define task_css_set_check(task, __c) \
|
||||
rcu_dereference_check((task)->cgroups, \
|
||||
@@ -704,6 +715,8 @@ struct cgroup;
|
||||
static inline u64 cgroup_id(const struct cgroup *cgrp) { return 1; }
|
||||
static inline void css_get(struct cgroup_subsys_state *css) {}
|
||||
static inline void css_put(struct cgroup_subsys_state *css) {}
|
||||
+static inline void cgroup_lock(void) {}
|
||||
+static inline void cgroup_unlock(void) {}
|
||||
static inline int cgroup_attach_task_all(struct task_struct *from,
|
||||
struct task_struct *t) { return 0; }
|
||||
static inline int cgroupstats_build(struct cgroupstats *stats,
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,178 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id C5A9BC4332B
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 90B8C64F1F
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233424AbhCMH6i (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:38 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58970 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232431AbhCMH6D (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:03 -0500
|
||||
Received: from mail-yb1-xb4a.google.com (mail-yb1-xb4a.google.com [IPv6:2607:f8b0:4864:20::b4a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A425FC061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:03 -0800 (PST)
|
||||
Received: by mail-yb1-xb4a.google.com with SMTP id 194so31802025ybl.5
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:03 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=773qLo/LiVz4n2L5CNuvuPAbdhL5vI+dQXWkGfq22YM=;
|
||||
b=s62F923cqY3HHxlJ4hYL4HxcRTUA1o1Vmr0HgcffuxiRKFFBC1czWP98NMUIxWHBf1
|
||||
ZTyWeNYix1pSuyOzyeK0NFpxLIWOmX10rPMvqWp8DuHg1yJhrNIGNko3fZT0atoX3aT9
|
||||
tvbuoR86gyhnQZ8eh7p7K/l32hNMDiL/9yg2skyWxrtzqXc2LkdkDBaiklyidpzGD9Xo
|
||||
glkEqmmHlh+PbMf1URYMZzEcs1zoLYSWmku5OQ0gpaw9yflCHjp7u8qrrfyCRliYK3I/
|
||||
Tc+BFkGgrB7u8ficVc0QKkIHZrZFoWgOnbQ0s8MxrT5IfVlLG0WbP3MEYNuJZFSmG8zL
|
||||
SKVQ==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=773qLo/LiVz4n2L5CNuvuPAbdhL5vI+dQXWkGfq22YM=;
|
||||
b=JutL0wSOtSKnXJpfp0Rn/HxX7HIFKRMSUwsEChk8vd4csU2mQte1wA+/+UuChaDIbU
|
||||
LAbDmBYxJhnK4nlISGat+zJubGDWfCTB+UZ0ZMedNwvo4kQ6wCMcrBVBswWbPfpCjDwr
|
||||
A4KWgVBEKj1hggrx43gbsIj1+nseOCIQxhyAyqUZPXMWyh5DbkzFwS/Ofm/k9MlAtqkm
|
||||
kxvprFWjiL/B2UVHRa6QH0Pd81vDVjQVhL1VANnhSRBRqVhMl9CKh6LDeEXIQ/j/SUW1
|
||||
sU5WIzhVZuh5Ce8LmXpg49O0w7XWFKmLxS65P39JtYklewPiPLasFUZmGGQIW0YkgSAb
|
||||
ikpA==
|
||||
X-Gm-Message-State: AOAM531sNbnzQRY0viG10kk0YQk3CPKaMfG7csYITYFCtPUjz1sM9Whr
|
||||
xig3F1mAxIB/3uXuYRA3nVADy29ViV4=
|
||||
X-Google-Smtp-Source: ABdhPJyM3uGtugEuR+BtqyW7Pcf+QxhuRuUSNVC/LK4e6LJubLVomvaz1At1w7Vl14tsop0cWxsmMMW22Kg=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a25:d84b:: with SMTP id p72mr22707445ybg.272.1615622282832;
|
||||
Fri, 12 Mar 2021 23:58:02 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:38 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-6-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 05/14] mm/swap.c: export activate_page()
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-6-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Export activate_page(), which is a merger between the existing
|
||||
activate_page() and __lru_cache_activate_page(), so it can be used to
|
||||
activate pages that are already on lru or queued in lru_pvecs.lru_add.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/swap.h | 1 +
|
||||
mm/swap.c | 28 +++++++++++++++-------------
|
||||
2 files changed, 16 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/include/linux/swap.h b/include/linux/swap.h
|
||||
index 4cc6ec3bf0ab..de2bbbf181ba 100644
|
||||
--- a/include/linux/swap.h
|
||||
+++ b/include/linux/swap.h
|
||||
@@ -344,6 +344,7 @@ extern void lru_add_drain_cpu(int cpu);
|
||||
extern void lru_add_drain_cpu_zone(struct zone *zone);
|
||||
extern void lru_add_drain_all(void);
|
||||
extern void rotate_reclaimable_page(struct page *page);
|
||||
+extern void activate_page(struct page *page);
|
||||
extern void deactivate_file_page(struct page *page);
|
||||
extern void deactivate_page(struct page *page);
|
||||
extern void mark_page_lazyfree(struct page *page);
|
||||
diff --git a/mm/swap.c b/mm/swap.c
|
||||
index 31b844d4ed94..f20ed56ebbbf 100644
|
||||
--- a/mm/swap.c
|
||||
+++ b/mm/swap.c
|
||||
@@ -334,7 +334,7 @@ static bool need_activate_page_drain(int cpu)
|
||||
return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0;
|
||||
}
|
||||
|
||||
-static void activate_page(struct page *page)
|
||||
+static void activate_page_on_lru(struct page *page)
|
||||
{
|
||||
page = compound_head(page);
|
||||
if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
|
||||
@@ -354,7 +354,7 @@ static inline void activate_page_drain(int cpu)
|
||||
{
|
||||
}
|
||||
|
||||
-static void activate_page(struct page *page)
|
||||
+static void activate_page_on_lru(struct page *page)
|
||||
{
|
||||
struct lruvec *lruvec;
|
||||
|
||||
@@ -368,11 +368,22 @@ static void activate_page(struct page *page)
|
||||
}
|
||||
#endif
|
||||
|
||||
-static void __lru_cache_activate_page(struct page *page)
|
||||
+/*
|
||||
+ * If the page is on the LRU, queue it for activation via
|
||||
+ * lru_pvecs.activate_page. Otherwise, assume the page is on a
|
||||
+ * pagevec, mark it active and it'll be moved to the active
|
||||
+ * LRU on the next drain.
|
||||
+ */
|
||||
+void activate_page(struct page *page)
|
||||
{
|
||||
struct pagevec *pvec;
|
||||
int i;
|
||||
|
||||
+ if (PageLRU(page)) {
|
||||
+ activate_page_on_lru(page);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
local_lock(&lru_pvecs.lock);
|
||||
pvec = this_cpu_ptr(&lru_pvecs.lru_add);
|
||||
|
||||
@@ -421,16 +432,7 @@ void mark_page_accessed(struct page *page)
|
||||
* evictable page accessed has no effect.
|
||||
*/
|
||||
} else if (!PageActive(page)) {
|
||||
- /*
|
||||
- * If the page is on the LRU, queue it for activation via
|
||||
- * lru_pvecs.activate_page. Otherwise, assume the page is on a
|
||||
- * pagevec, mark it active and it'll be moved to the active
|
||||
- * LRU on the next drain.
|
||||
- */
|
||||
- if (PageLRU(page))
|
||||
- activate_page(page);
|
||||
- else
|
||||
- __lru_cache_activate_page(page);
|
||||
+ activate_page(page);
|
||||
ClearPageReferenced(page);
|
||||
workingset_activation(page);
|
||||
}
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,202 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id CFB78C43331
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id A37AF64F1E
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233446AbhCMH6j (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:39 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58976 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232627AbhCMH6F (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:05 -0500
|
||||
Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF963C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:04 -0800 (PST)
|
||||
Received: by mail-qt1-x84a.google.com with SMTP id a16so3377560qtw.1
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:04 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=9FOrNXENvEBq+xjcXdvWYV76Tj/52PeZfpdHZpBdeTw=;
|
||||
b=CZNFSLn1Vr+7g91u2WdSPY2RASOoMeGVnEu8XS9ogwps7Gq+7F5umE3fWsyowJpBWD
|
||||
/BpSgazEV0uTx/142ccxmLjj6Tc5kR7KGsb79Ptj4azaGNuJBT032A7MXAqita6Xkryl
|
||||
6IanFkwVS4tC+SsZAZtk+kuQzdp1pO5Pnx+cXwdQzEVQmCkWjuUnjKzoEPGf4IlnkcFb
|
||||
QOa5YU3bEwcfmAFIwkc2tWsdZ2h8rKKycxzT/zHBKI265GiGZGNofgaHIdU33DduoJGc
|
||||
Q3y72dvencUMJG5nccrm3sqMC+9s98wb5AiyP7gwQH8cNu/oUBPDF/k1zMnv1QbL0y4q
|
||||
Wkmw==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=9FOrNXENvEBq+xjcXdvWYV76Tj/52PeZfpdHZpBdeTw=;
|
||||
b=dwfL2qqtOLyHknmJLTbNquIIE99M3co4RRcjM8ZHW7E3b22r0qS7/uSdIuLxhwPvQA
|
||||
Y3LL2jZN2S3rNEY31iqcQo0XPmDjtQwb13jd9vmVGL+LLS5tszC4uUapyiV0oPCH5uwL
|
||||
smIUxO+PPvwuZT1NgqDpJ05pyAL6HNc5tjDAhFLsgZFN/eS2938P25wiN4+HDX1vPlLc
|
||||
PXD85IpbqplkrTukFj4waHLj2xp8v/FPA9XzbBiYpaKEr1bL5w6oyKCxl6mnhZr0A9h6
|
||||
m3QW2oQAPQpKG6YqSR4gB8S9wvQ5RcQOj/4jcVgdKH2lIq48/Tc9tYuJNF3HuISISSMR
|
||||
K2Aw==
|
||||
X-Gm-Message-State: AOAM530QAe48ahNQ/TdZi8OsNzl8PRShs8X4B4mC6ejSQSSJgG9mU0dS
|
||||
C8+Z0ZLOLiEDu/n5izcyhgbt0bjgPuM=
|
||||
X-Google-Smtp-Source: ABdhPJx3v9fo9fGIto8kHzW5LTGjVA6UTKRtTeuo4NwnDLlQop9mIBVZK8pHZLGtADbIHe5kSQ6HeS7hVrU=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a0c:cb0c:: with SMTP id o12mr15467752qvk.54.1615622284101;
|
||||
Fri, 12 Mar 2021 23:58:04 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:39 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-7-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 06/14] mm, x86: support the access bit on non-leaf PMD entries
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-7-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Some architectures support the accessed bit on non-leaf PMD entries
|
||||
(parents) in addition to leaf PTE entries (children) where pages are
|
||||
mapped, e.g., x86_64 sets the accessed bit on a parent when using it
|
||||
as part of linear-address translation [1]. Page table walkers who are
|
||||
interested in the accessed bit on children can take advantage of this:
|
||||
they do not need to search the children when the accessed bit is not
|
||||
set on a parent, given that they have previously cleared the accessed
|
||||
bit on this parent in addition to its children.
|
||||
|
||||
[1]: Intel 64 and IA-32 Architectures Software Developer's Manual
|
||||
Volume 3 (October 2019), section 4.8
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
arch/Kconfig | 8 ++++++++
|
||||
arch/x86/Kconfig | 1 +
|
||||
arch/x86/include/asm/pgtable.h | 2 +-
|
||||
arch/x86/mm/pgtable.c | 5 ++++-
|
||||
include/linux/pgtable.h | 4 ++--
|
||||
5 files changed, 16 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/arch/Kconfig b/arch/Kconfig
|
||||
index 2bb30673d8e6..137446d17732 100644
|
||||
--- a/arch/Kconfig
|
||||
+++ b/arch/Kconfig
|
||||
@@ -783,6 +783,14 @@ config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
config HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
|
||||
bool
|
||||
|
||||
+config HAVE_ARCH_PARENT_PMD_YOUNG
|
||||
+ bool
|
||||
+ help
|
||||
+ Architectures that select this are able to set the accessed bit on
|
||||
+ non-leaf PMD entries in addition to leaf PTE entries where pages are
|
||||
+ mapped. For them, page table walkers that clear the accessed bit may
|
||||
+ stop at non-leaf PMD entries when they do not see the accessed bit.
|
||||
+
|
||||
config HAVE_ARCH_HUGE_VMAP
|
||||
bool
|
||||
|
||||
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
||||
index 2792879d398e..b5972eb82337 100644
|
||||
--- a/arch/x86/Kconfig
|
||||
+++ b/arch/x86/Kconfig
|
||||
@@ -163,6 +163,7 @@ config X86
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD if X86_64
|
||||
+ select HAVE_ARCH_PARENT_PMD_YOUNG if X86_64
|
||||
select HAVE_ARCH_USERFAULTFD_WP if X86_64 && USERFAULTFD
|
||||
select HAVE_ARCH_VMAP_STACK if X86_64
|
||||
select HAVE_ARCH_WITHIN_STACK_FRAMES
|
||||
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
|
||||
index a02c67291cfc..a6b5cfe1fc5a 100644
|
||||
--- a/arch/x86/include/asm/pgtable.h
|
||||
+++ b/arch/x86/include/asm/pgtable.h
|
||||
@@ -846,7 +846,7 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
|
||||
|
||||
static inline int pmd_bad(pmd_t pmd)
|
||||
{
|
||||
- return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE;
|
||||
+ return ((pmd_flags(pmd) | _PAGE_ACCESSED) & ~_PAGE_USER) != _KERNPG_TABLE;
|
||||
}
|
||||
|
||||
static inline unsigned long pages_to_mb(unsigned long npg)
|
||||
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
|
||||
index f6a9e2e36642..1c27e6f43f80 100644
|
||||
--- a/arch/x86/mm/pgtable.c
|
||||
+++ b/arch/x86/mm/pgtable.c
|
||||
@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma,
|
||||
return ret;
|
||||
}
|
||||
|
||||
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HAVE_ARCH_PARENT_PMD_YOUNG)
|
||||
int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
||||
unsigned long addr, pmd_t *pmdp)
|
||||
{
|
||||
@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
||||
|
||||
return ret;
|
||||
}
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
int pudp_test_and_clear_young(struct vm_area_struct *vma,
|
||||
unsigned long addr, pud_t *pudp)
|
||||
{
|
||||
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
|
||||
index 5e772392a379..08dd9b8c055a 100644
|
||||
--- a/include/linux/pgtable.h
|
||||
+++ b/include/linux/pgtable.h
|
||||
@@ -193,7 +193,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
|
||||
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HAVE_ARCH_PARENT_PMD_YOUNG)
|
||||
static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
||||
unsigned long address,
|
||||
pmd_t *pmdp)
|
||||
@@ -214,7 +214,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
|
||||
BUILD_BUG();
|
||||
return 0;
|
||||
}
|
||||
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HAVE_ARCH_PARENT_PMD_YOUNG */
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,144 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id E3438C43332
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id C990264F1D
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233489AbhCMH6l (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:41 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58984 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232702AbhCMH6G (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:06 -0500
|
||||
Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F2FEC061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:06 -0800 (PST)
|
||||
Received: by mail-yb1-xb49.google.com with SMTP id j4so31727869ybt.23
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:06 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=sM28HXat3Ro78N+fdELj5tA2TTORYcmSJRB7y0xn668=;
|
||||
b=TkMSfULPVVqqEs8nJoS183e8mdw8yepLBTDn2eNINUqggav0COpVRzISc3zd89NvN9
|
||||
G1/R3rFQNbXB4Mc0QhWaGTD1Fq53asLndQ1E2i8CSZ95KHVj8MUNkswp9uk2yDDtfErk
|
||||
Sbw+4/WN0WzNqVfegG6JQMHiPP9iXEqGFYVgSZLK8flNYafDsz7FgT4K+/4AxxZLFwj6
|
||||
mhv5FnKYJxQDSuEX1b3S54OYObhuyWJnGpPGLfPwfJ/quLWGTNO+ZIAeb5KMAmBdnEKV
|
||||
rF1QTgCoPPMsWsShNKe8BsfaSKCMVGiSbi90ZFx8J0HHcn4GpbXrkYUuLSCcm0F4KYI7
|
||||
fQQw==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=sM28HXat3Ro78N+fdELj5tA2TTORYcmSJRB7y0xn668=;
|
||||
b=RiLWz/T/zcexV2Bsbw7YiZb7BINvMGTgl79XdA6B/OHzniNtpaj8nGzPvt6kerrgat
|
||||
ur0TSQPmxqyehHvbKNQ7mbs/PTvniAuwd45+Ub0Vv+9NgoF9uTsNfAK7Vd4jQHOWOvhm
|
||||
m1E6fZ25eW7KaMDTCBmRrCvIXIblvOe8PuRRsZqiT991bZ5mnSFynpVrpRLetwouPyGk
|
||||
pSnxWX8BcM/e6hZIrC3KPP2PeXLt4ehMvZ9h9fIeH0DezONgDMKpjc0TdLhdm0Z+EAPP
|
||||
gLoBDsqcG45NgWLNP2KcFrcDXtjwD+f9JAiMZvrNFb7RI7F78RYvzjAuegAab8YW/u+o
|
||||
Nkzg==
|
||||
X-Gm-Message-State: AOAM530brY8KWy4SQHMkv1r6LKzek0Cq4xuuj7kcDTW0m3zhQz3OLAJt
|
||||
GTHrB+1mfPD6eAMjZFoSYPQ7AwnDTeo=
|
||||
X-Google-Smtp-Source: ABdhPJzZYSt4fmXD7VdJ6T+CnbKC2/TjZT+i4G4gEva1Omiq/qzC/4JrVYLGPq2Q22anUOeAEZWsql+skQ8=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a25:2308:: with SMTP id j8mr24384456ybj.474.1615622285438;
|
||||
Fri, 12 Mar 2021 23:58:05 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:40 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-8-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 07/14] mm/pagewalk.c: add pud_entry_post() for post-order traversals
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-8-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Add a new callback pud_entry_post() to struct mm_walk_ops so that page
|
||||
table walkers can visit the non-leaf PMD entries of a PUD entry after
|
||||
they have visited with the leaf PTE entries. This allows page table
|
||||
walkers who clear the accessed bit to take advantage of the last
|
||||
commit, in a similar way walk_pte_range() works for the PTE entries of
|
||||
a PMD entry: they only need to take PTL once to search all the child
|
||||
entries of a parent entry.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
include/linux/pagewalk.h | 4 ++++
|
||||
mm/pagewalk.c | 5 +++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/include/linux/pagewalk.h b/include/linux/pagewalk.h
|
||||
index b1cb6b753abb..2b68ae9d27d3 100644
|
||||
--- a/include/linux/pagewalk.h
|
||||
+++ b/include/linux/pagewalk.h
|
||||
@@ -11,6 +11,8 @@ struct mm_walk;
|
||||
* @pgd_entry: if set, called for each non-empty PGD (top-level) entry
|
||||
* @p4d_entry: if set, called for each non-empty P4D entry
|
||||
* @pud_entry: if set, called for each non-empty PUD entry
|
||||
+ * @pud_entry_post: if set, called for each non-empty PUD entry after
|
||||
+ * pmd_entry is called, for post-order traversal.
|
||||
* @pmd_entry: if set, called for each non-empty PMD entry
|
||||
* this handler is required to be able to handle
|
||||
* pmd_trans_huge() pmds. They may simply choose to
|
||||
@@ -41,6 +43,8 @@ struct mm_walk_ops {
|
||||
unsigned long next, struct mm_walk *walk);
|
||||
int (*pud_entry)(pud_t *pud, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk);
|
||||
+ int (*pud_entry_post)(pud_t *pud, unsigned long addr,
|
||||
+ unsigned long next, struct mm_walk *walk);
|
||||
int (*pmd_entry)(pmd_t *pmd, unsigned long addr,
|
||||
unsigned long next, struct mm_walk *walk);
|
||||
int (*pte_entry)(pte_t *pte, unsigned long addr,
|
||||
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
|
||||
index e81640d9f177..8ed1533f7eda 100644
|
||||
--- a/mm/pagewalk.c
|
||||
+++ b/mm/pagewalk.c
|
||||
@@ -160,6 +160,11 @@ static int walk_pud_range(p4d_t *p4d, unsigned long addr, unsigned long end,
|
||||
err = walk_pmd_range(pud, addr, next, walk);
|
||||
if (err)
|
||||
break;
|
||||
+
|
||||
+ if (ops->pud_entry_post)
|
||||
+ err = ops->pud_entry_post(pud, addr, next, walk);
|
||||
+ if (err)
|
||||
+ break;
|
||||
} while (pud++, addr = next, addr != end);
|
||||
|
||||
return err;
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,311 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id CBC4DC4332D
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id B8A3D64ECE
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233468AbhCMH6l (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:41 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58990 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232705AbhCMH6I (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:08 -0500
|
||||
Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A5BF1C061761
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:07 -0800 (PST)
|
||||
Received: by mail-qk1-x749.google.com with SMTP id i188so19867209qkd.7
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:07 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=Y7HI6Iu8cEpN4/cKvfcV1g+GhNxN+RuODBCey3P9ub4=;
|
||||
b=Yxxt5mdzkudc9JV5Q09FDlj0cvp1kmfCXxaVjGD5K0eCTz/So1vsV5U0rgmXDgA+oo
|
||||
I0A6T+8UZJmQiHjXDXECTBckUL0jnXMRgRm7XVaG53YB34iWjqO40F4CKKEh9+/OoVRc
|
||||
G0AmzhscUbBJ/kam3+ejsn6XT8HmEmL1E1JV5ccYQd+ZntwFpRDTuwloc8JJwbzlOPz6
|
||||
/TmQCN3DlJawauHo+hK8esqlLBqlUo0Hc3ctZf6lI6jfTJ6xP19kgHg147e6ddt/0Gru
|
||||
4TRJ0LLQctTAhahAckLyUPLY8X0ofJQRXl5IFVx653ZZtEjcg5D9kIYZI+E7lddJGHTM
|
||||
WCSQ==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=Y7HI6Iu8cEpN4/cKvfcV1g+GhNxN+RuODBCey3P9ub4=;
|
||||
b=IhPlACmRhDBTPdmCHr0Oo1gV9hWUVpXkJQAh9lb+wytYYH7q3Kq7e+gKEZ0WvXAxP5
|
||||
HCkzZEXo0KeDSrSNfpNxh8YUrLoNxRyc67U6jB0GE7MI8jH4hpyANf1w/gGK8VfBJVP6
|
||||
HEd0MgT957tjxC4w5s2bFihlDvVujIJLQPYS+KO24VxvtbXLbjOayAHo8fH37VLxQ9U2
|
||||
nOkP5ADzrpG+7bfsI2JutdLL5J6KjOX/ix5YTdFiiS1XlDgF+UDcwUkwnju04+gULHCK
|
||||
SWuoOrT0DOfqlcQ4ome3RlXCB1UU/RCIPUUA06Y1a7h09m5zX6C1pqv0hnFWEk1Ehj8t
|
||||
sE+g==
|
||||
X-Gm-Message-State: AOAM533FjF5wfsmOCevkWqM2Zy0aRGz/n1+9ldB7hstZ21MlGbAcnU9S
|
||||
iwofL/8D5KT2K6tTLoKvMx4do3+86Ss=
|
||||
X-Google-Smtp-Source: ABdhPJwaHhrMfJqAPFj0pJIH6XbHZzHvvKGA6xcQa4GVhmvHaXMnKKa3+FEHfHSk+8gEmFOMqKskjMN6bjo=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:ad4:50c7:: with SMTP id e7mr1747988qvq.58.1615622286760;
|
||||
Fri, 12 Mar 2021 23:58:06 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:41 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-9-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 08/14] mm/vmscan.c: refactor shrink_node()
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-9-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Heuristics in shrink_node() are rather independent and can be
|
||||
refactored into a separate function to improve readability.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
mm/vmscan.c | 186 +++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 98 insertions(+), 88 deletions(-)
|
||||
|
||||
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||
index 562e87cbd7a1..1a24d2e0a4cb 100644
|
||||
--- a/mm/vmscan.c
|
||||
+++ b/mm/vmscan.c
|
||||
@@ -2224,6 +2224,103 @@ enum scan_balance {
|
||||
SCAN_FILE,
|
||||
};
|
||||
|
||||
+static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc)
|
||||
+{
|
||||
+ unsigned long file;
|
||||
+ struct lruvec *target_lruvec;
|
||||
+
|
||||
+ target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);
|
||||
+
|
||||
+ /*
|
||||
+ * Determine the scan balance between anon and file LRUs.
|
||||
+ */
|
||||
+ spin_lock_irq(&target_lruvec->lru_lock);
|
||||
+ sc->anon_cost = target_lruvec->anon_cost;
|
||||
+ sc->file_cost = target_lruvec->file_cost;
|
||||
+ spin_unlock_irq(&target_lruvec->lru_lock);
|
||||
+
|
||||
+ /*
|
||||
+ * Target desirable inactive:active list ratios for the anon
|
||||
+ * and file LRU lists.
|
||||
+ */
|
||||
+ if (!sc->force_deactivate) {
|
||||
+ unsigned long refaults;
|
||||
+
|
||||
+ refaults = lruvec_page_state(target_lruvec,
|
||||
+ WORKINGSET_ACTIVATE_ANON);
|
||||
+ if (refaults != target_lruvec->refaults[0] ||
|
||||
+ inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
|
||||
+ sc->may_deactivate |= DEACTIVATE_ANON;
|
||||
+ else
|
||||
+ sc->may_deactivate &= ~DEACTIVATE_ANON;
|
||||
+
|
||||
+ /*
|
||||
+ * When refaults are being observed, it means a new
|
||||
+ * workingset is being established. Deactivate to get
|
||||
+ * rid of any stale active pages quickly.
|
||||
+ */
|
||||
+ refaults = lruvec_page_state(target_lruvec,
|
||||
+ WORKINGSET_ACTIVATE_FILE);
|
||||
+ if (refaults != target_lruvec->refaults[1] ||
|
||||
+ inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
|
||||
+ sc->may_deactivate |= DEACTIVATE_FILE;
|
||||
+ else
|
||||
+ sc->may_deactivate &= ~DEACTIVATE_FILE;
|
||||
+ } else
|
||||
+ sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;
|
||||
+
|
||||
+ /*
|
||||
+ * If we have plenty of inactive file pages that aren't
|
||||
+ * thrashing, try to reclaim those first before touching
|
||||
+ * anonymous pages.
|
||||
+ */
|
||||
+ file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
|
||||
+ if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
|
||||
+ sc->cache_trim_mode = 1;
|
||||
+ else
|
||||
+ sc->cache_trim_mode = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Prevent the reclaimer from falling into the cache trap: as
|
||||
+ * cache pages start out inactive, every cache fault will tip
|
||||
+ * the scan balance towards the file LRU. And as the file LRU
|
||||
+ * shrinks, so does the window for rotation from references.
|
||||
+ * This means we have a runaway feedback loop where a tiny
|
||||
+ * thrashing file LRU becomes infinitely more attractive than
|
||||
+ * anon pages. Try to detect this based on file LRU size.
|
||||
+ */
|
||||
+ if (!cgroup_reclaim(sc)) {
|
||||
+ unsigned long total_high_wmark = 0;
|
||||
+ unsigned long free, anon;
|
||||
+ int z;
|
||||
+
|
||||
+ free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
|
||||
+ file = node_page_state(pgdat, NR_ACTIVE_FILE) +
|
||||
+ node_page_state(pgdat, NR_INACTIVE_FILE);
|
||||
+
|
||||
+ for (z = 0; z < MAX_NR_ZONES; z++) {
|
||||
+ struct zone *zone = &pgdat->node_zones[z];
|
||||
+
|
||||
+ if (!managed_zone(zone))
|
||||
+ continue;
|
||||
+
|
||||
+ total_high_wmark += high_wmark_pages(zone);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Consider anon: if that's low too, this isn't a
|
||||
+ * runaway file reclaim problem, but rather just
|
||||
+ * extreme pressure. Reclaim as per usual then.
|
||||
+ */
|
||||
+ anon = node_page_state(pgdat, NR_INACTIVE_ANON);
|
||||
+
|
||||
+ sc->file_is_tiny =
|
||||
+ file + free <= total_high_wmark &&
|
||||
+ !(sc->may_deactivate & DEACTIVATE_ANON) &&
|
||||
+ anon >> sc->priority;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Determine how aggressively the anon and file LRU lists should be
|
||||
* scanned. The relative value of each set of LRU lists is determined
|
||||
@@ -2669,7 +2766,6 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
|
||||
unsigned long nr_reclaimed, nr_scanned;
|
||||
struct lruvec *target_lruvec;
|
||||
bool reclaimable = false;
|
||||
- unsigned long file;
|
||||
|
||||
target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);
|
||||
|
||||
@@ -2679,93 +2775,7 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
|
||||
nr_reclaimed = sc->nr_reclaimed;
|
||||
nr_scanned = sc->nr_scanned;
|
||||
|
||||
- /*
|
||||
- * Determine the scan balance between anon and file LRUs.
|
||||
- */
|
||||
- spin_lock_irq(&target_lruvec->lru_lock);
|
||||
- sc->anon_cost = target_lruvec->anon_cost;
|
||||
- sc->file_cost = target_lruvec->file_cost;
|
||||
- spin_unlock_irq(&target_lruvec->lru_lock);
|
||||
-
|
||||
- /*
|
||||
- * Target desirable inactive:active list ratios for the anon
|
||||
- * and file LRU lists.
|
||||
- */
|
||||
- if (!sc->force_deactivate) {
|
||||
- unsigned long refaults;
|
||||
-
|
||||
- refaults = lruvec_page_state(target_lruvec,
|
||||
- WORKINGSET_ACTIVATE_ANON);
|
||||
- if (refaults != target_lruvec->refaults[0] ||
|
||||
- inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
|
||||
- sc->may_deactivate |= DEACTIVATE_ANON;
|
||||
- else
|
||||
- sc->may_deactivate &= ~DEACTIVATE_ANON;
|
||||
-
|
||||
- /*
|
||||
- * When refaults are being observed, it means a new
|
||||
- * workingset is being established. Deactivate to get
|
||||
- * rid of any stale active pages quickly.
|
||||
- */
|
||||
- refaults = lruvec_page_state(target_lruvec,
|
||||
- WORKINGSET_ACTIVATE_FILE);
|
||||
- if (refaults != target_lruvec->refaults[1] ||
|
||||
- inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
|
||||
- sc->may_deactivate |= DEACTIVATE_FILE;
|
||||
- else
|
||||
- sc->may_deactivate &= ~DEACTIVATE_FILE;
|
||||
- } else
|
||||
- sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;
|
||||
-
|
||||
- /*
|
||||
- * If we have plenty of inactive file pages that aren't
|
||||
- * thrashing, try to reclaim those first before touching
|
||||
- * anonymous pages.
|
||||
- */
|
||||
- file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
|
||||
- if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
|
||||
- sc->cache_trim_mode = 1;
|
||||
- else
|
||||
- sc->cache_trim_mode = 0;
|
||||
-
|
||||
- /*
|
||||
- * Prevent the reclaimer from falling into the cache trap: as
|
||||
- * cache pages start out inactive, every cache fault will tip
|
||||
- * the scan balance towards the file LRU. And as the file LRU
|
||||
- * shrinks, so does the window for rotation from references.
|
||||
- * This means we have a runaway feedback loop where a tiny
|
||||
- * thrashing file LRU becomes infinitely more attractive than
|
||||
- * anon pages. Try to detect this based on file LRU size.
|
||||
- */
|
||||
- if (!cgroup_reclaim(sc)) {
|
||||
- unsigned long total_high_wmark = 0;
|
||||
- unsigned long free, anon;
|
||||
- int z;
|
||||
-
|
||||
- free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
|
||||
- file = node_page_state(pgdat, NR_ACTIVE_FILE) +
|
||||
- node_page_state(pgdat, NR_INACTIVE_FILE);
|
||||
-
|
||||
- for (z = 0; z < MAX_NR_ZONES; z++) {
|
||||
- struct zone *zone = &pgdat->node_zones[z];
|
||||
- if (!managed_zone(zone))
|
||||
- continue;
|
||||
-
|
||||
- total_high_wmark += high_wmark_pages(zone);
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * Consider anon: if that's low too, this isn't a
|
||||
- * runaway file reclaim problem, but rather just
|
||||
- * extreme pressure. Reclaim as per usual then.
|
||||
- */
|
||||
- anon = node_page_state(pgdat, NR_INACTIVE_ANON);
|
||||
-
|
||||
- sc->file_is_tiny =
|
||||
- file + free <= total_high_wmark &&
|
||||
- !(sc->may_deactivate & DEACTIVATE_ANON) &&
|
||||
- anon >> sc->priority;
|
||||
- }
|
||||
+ prepare_scan_count(pgdat, sc);
|
||||
|
||||
shrink_node_memcgs(pgdat, sc);
|
||||
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,749 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 0360FC4332E
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id E377164F1E
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:06 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233512AbhCMH6m (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:42 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58996 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232709AbhCMH6J (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:09 -0500
|
||||
Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0386C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:08 -0800 (PST)
|
||||
Received: by mail-qk1-x749.google.com with SMTP id h134so19965073qke.1
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:08 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=7aNjMZwXzkZhXFvRmRWQJ8BQ+8lusUpXBFHauhX2ubg=;
|
||||
b=rXTENBp2Eom7kHIkgQlwaM0zAjOFi5gmzyQ9fUwZQJp4tjb12IZlxofeTMBMfAGa/r
|
||||
L4Ghc3L00KAFuV2LaP7uyJH7AsU4qMsIGq1k1CkPhOMdO7EV4BDTbgd4vEf68FTu94xi
|
||||
vXrlWZYOskUlSCRkRuZtatqD65DIQyZkjMKdk2hKBnk6QJmcpPB6RWsgv88u3qVxEBZx
|
||||
iiEhsjInkvzH6qtUYApIn6cqLI7Fd+8G1HrkDMmx13q4PXkdeunv1Az0GMeKsUNzGYYs
|
||||
e4N6HA5c9v+Un/TrJ4yGhAbzwYgJSTU4Xrzr5/9QWPKNcFUkXgh0KosPnfdwtEviCEBv
|
||||
6pmg==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=7aNjMZwXzkZhXFvRmRWQJ8BQ+8lusUpXBFHauhX2ubg=;
|
||||
b=YWegDePJI84B+MDTMEsT3ncwRQ6xqfLVLoxaVcjlpDCwizTWwtdyaGlleP04JZ5N+5
|
||||
AkfxqK0DQUXAyBBm7v7dckpiAm/jUldpE5n9Uh4ZmUf6oJt35HCt8C2aWgCxnV6YH3xL
|
||||
86xAS1GV/vZb1DaCjG3Fa6mqH6EJPd/c9xZPVGxYnPYoLGKZDyI2j04nHrPyKye2NZMZ
|
||||
HQohID0ijQkEqVBAuj4H9CyNS/XwXkM24UKVFyYk6hKAmmMp/Na4vDYy5LN2rRariQhj
|
||||
uPMou6WiKPb6Ph6mcd35an6LnCUHgzKHE2Tu+AnxXcrqTu9ijLJ5E6/FY2cCcrIEXK7S
|
||||
VoHQ==
|
||||
X-Gm-Message-State: AOAM530An7ZbSyg9gdVA41zNIb/3lnpDD6ALzchYWG8q+sQY4pqkltfs
|
||||
r5qU0vNqoKeYC+YKblti/xtfb5zboKM=
|
||||
X-Google-Smtp-Source: ABdhPJxXAZ3oX16iFANwEv0b7ybctnsmZAK24tAjZNdUXRU2Fm50sCFyGpIqOrn3ll+aJz5mcnB7+tMAtOQ=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a0c:b8a3:: with SMTP id y35mr15828724qvf.23.1615622288067;
|
||||
Fri, 12 Mar 2021 23:58:08 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:42 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-10-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 09/14] mm: multigenerational lru: mm_struct list
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-10-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Add an infrastructure that maintains either a system-wide mm_struct
|
||||
list or per-memcg mm_struct lists. Multiple threads can concurrently
|
||||
work on the same mm_struct list, and each of them will be given a
|
||||
different mm_struct. Those who finish early can optionally wait on the
|
||||
rest after the iterator has reached the end of the list.
|
||||
|
||||
This infrastructure also tracks whether an mm_struct is being used on
|
||||
any CPUs or has been used since the last time a worker looked at it.
|
||||
In other words, workers will not be given an mm_struct that belongs to
|
||||
a process that has been sleeping.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
fs/exec.c | 2 +
|
||||
include/linux/memcontrol.h | 4 +
|
||||
include/linux/mm_types.h | 135 +++++++++++++++++++
|
||||
include/linux/mmzone.h | 2 -
|
||||
kernel/exit.c | 1 +
|
||||
kernel/fork.c | 10 ++
|
||||
kernel/kthread.c | 1 +
|
||||
kernel/sched/core.c | 2 +
|
||||
mm/memcontrol.c | 28 ++++
|
||||
mm/vmscan.c | 263 +++++++++++++++++++++++++++++++++++++
|
||||
10 files changed, 446 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/fs/exec.c b/fs/exec.c
|
||||
index 18594f11c31f..c691d4d7720c 100644
|
||||
--- a/fs/exec.c
|
||||
+++ b/fs/exec.c
|
||||
@@ -1008,6 +1008,7 @@ static int exec_mmap(struct mm_struct *mm)
|
||||
active_mm = tsk->active_mm;
|
||||
tsk->active_mm = mm;
|
||||
tsk->mm = mm;
|
||||
+ lru_gen_add_mm(mm);
|
||||
/*
|
||||
* This prevents preemption while active_mm is being loaded and
|
||||
* it and mm are being updated, which could cause problems for
|
||||
@@ -1018,6 +1019,7 @@ static int exec_mmap(struct mm_struct *mm)
|
||||
if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
|
||||
local_irq_enable();
|
||||
activate_mm(active_mm, mm);
|
||||
+ lru_gen_switch_mm(active_mm, mm);
|
||||
if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM))
|
||||
local_irq_enable();
|
||||
tsk->mm->vmacache_seqnum = 0;
|
||||
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
|
||||
index f325aeb4b4e8..591557c5b7e2 100644
|
||||
--- a/include/linux/memcontrol.h
|
||||
+++ b/include/linux/memcontrol.h
|
||||
@@ -335,6 +335,10 @@ struct mem_cgroup {
|
||||
struct deferred_split deferred_split_queue;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_LRU_GEN
|
||||
+ struct lru_gen_mm_list *mm_list;
|
||||
+#endif
|
||||
+
|
||||
struct mem_cgroup_per_node *nodeinfo[0];
|
||||
/* WARNING: nodeinfo must be the last member here */
|
||||
};
|
||||
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
|
||||
index 0974ad501a47..b8a038a016f2 100644
|
||||
--- a/include/linux/mm_types.h
|
||||
+++ b/include/linux/mm_types.h
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <linux/page-flags-layout.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/seqlock.h>
|
||||
+#include <linux/nodemask.h>
|
||||
+#include <linux/mmdebug.h>
|
||||
|
||||
#include <asm/mmu.h>
|
||||
|
||||
@@ -382,6 +384,8 @@ struct core_state {
|
||||
struct completion startup;
|
||||
};
|
||||
|
||||
+#define ANON_AND_FILE 2
|
||||
+
|
||||
struct kioctx_table;
|
||||
struct mm_struct {
|
||||
struct {
|
||||
@@ -560,6 +564,22 @@ struct mm_struct {
|
||||
|
||||
#ifdef CONFIG_IOMMU_SUPPORT
|
||||
u32 pasid;
|
||||
+#endif
|
||||
+#ifdef CONFIG_LRU_GEN
|
||||
+ struct {
|
||||
+ /* node of a global or per-memcg mm list */
|
||||
+ struct list_head list;
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ /* points to memcg of the owner task above */
|
||||
+ struct mem_cgroup *memcg;
|
||||
+#endif
|
||||
+ /* indicates this mm has been used since last walk */
|
||||
+ nodemask_t nodes[ANON_AND_FILE];
|
||||
+#ifndef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
+ /* number of cpus that are using this mm */
|
||||
+ atomic_t nr_cpus;
|
||||
+#endif
|
||||
+ } lru_gen;
|
||||
#endif
|
||||
} __randomize_layout;
|
||||
|
||||
@@ -587,6 +607,121 @@ static inline cpumask_t *mm_cpumask(struct mm_struct *mm)
|
||||
return (struct cpumask *)&mm->cpu_bitmap;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_LRU_GEN
|
||||
+
|
||||
+struct lru_gen_mm_list {
|
||||
+ /* head of a global or per-memcg mm list */
|
||||
+ struct list_head head;
|
||||
+ /* protects the list */
|
||||
+ spinlock_t lock;
|
||||
+ struct {
|
||||
+ /* set to max_seq after each round of walk */
|
||||
+ unsigned long cur_seq;
|
||||
+ /* next mm on the list to walk */
|
||||
+ struct list_head *iter;
|
||||
+ /* to wait for last worker to finish */
|
||||
+ struct wait_queue_head wait;
|
||||
+ /* number of concurrent workers */
|
||||
+ int nr_workers;
|
||||
+ } nodes[0];
|
||||
+};
|
||||
+
|
||||
+void lru_gen_init_mm(struct mm_struct *mm);
|
||||
+void lru_gen_add_mm(struct mm_struct *mm);
|
||||
+void lru_gen_del_mm(struct mm_struct *mm);
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+int lru_gen_alloc_mm_list(struct mem_cgroup *memcg);
|
||||
+void lru_gen_free_mm_list(struct mem_cgroup *memcg);
|
||||
+void lru_gen_migrate_mm(struct mm_struct *mm);
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+ * Track usage so mms that haven't been used since last walk can be skipped.
|
||||
+ *
|
||||
+ * This function introduces a theoretical overhead for each mm switch, but it
|
||||
+ * hasn't been measurable.
|
||||
+ */
|
||||
+static inline void lru_gen_switch_mm(struct mm_struct *old, struct mm_struct *new)
|
||||
+{
|
||||
+ int file;
|
||||
+
|
||||
+ /* exclude init_mm, efi_mm, etc. */
|
||||
+ if (!core_kernel_data((unsigned long)old)) {
|
||||
+ VM_BUG_ON(old == &init_mm);
|
||||
+
|
||||
+ for (file = 0; file < ANON_AND_FILE; file++)
|
||||
+ nodes_setall(old->lru_gen.nodes[file]);
|
||||
+
|
||||
+#ifndef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
+ atomic_dec(&old->lru_gen.nr_cpus);
|
||||
+ VM_BUG_ON_MM(atomic_read(&old->lru_gen.nr_cpus) < 0, old);
|
||||
+#endif
|
||||
+ } else
|
||||
+ VM_BUG_ON_MM(READ_ONCE(old->lru_gen.list.prev) ||
|
||||
+ READ_ONCE(old->lru_gen.list.next), old);
|
||||
+
|
||||
+ if (!core_kernel_data((unsigned long)new)) {
|
||||
+ VM_BUG_ON(new == &init_mm);
|
||||
+
|
||||
+#ifndef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
+ atomic_inc(&new->lru_gen.nr_cpus);
|
||||
+ VM_BUG_ON_MM(atomic_read(&new->lru_gen.nr_cpus) < 0, new);
|
||||
+#endif
|
||||
+ } else
|
||||
+ VM_BUG_ON_MM(READ_ONCE(new->lru_gen.list.prev) ||
|
||||
+ READ_ONCE(new->lru_gen.list.next), new);
|
||||
+}
|
||||
+
|
||||
+/* Returns whether the mm is being used on any cpus. */
|
||||
+static inline bool lru_gen_mm_is_active(struct mm_struct *mm)
|
||||
+{
|
||||
+#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
+ return !cpumask_empty(mm_cpumask(mm));
|
||||
+#else
|
||||
+ return atomic_read(&mm->lru_gen.nr_cpus);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+#else /* CONFIG_LRU_GEN */
|
||||
+
|
||||
+static inline void lru_gen_init_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline void lru_gen_add_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline void lru_gen_del_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+static inline int lru_gen_alloc_mm_list(struct mem_cgroup *memcg)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline void lru_gen_free_mm_list(struct mem_cgroup *memcg)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline void lru_gen_migrate_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static inline void lru_gen_switch_mm(struct mm_struct *old, struct mm_struct *new)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline bool lru_gen_mm_is_active(struct mm_struct *mm)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+#endif /* CONFIG_LRU_GEN */
|
||||
+
|
||||
struct mmu_gather;
|
||||
extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm);
|
||||
extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm);
|
||||
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
|
||||
index 47946cec7584..a99a1050565a 100644
|
||||
--- a/include/linux/mmzone.h
|
||||
+++ b/include/linux/mmzone.h
|
||||
@@ -285,8 +285,6 @@ static inline bool is_active_lru(enum lru_list lru)
|
||||
return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE);
|
||||
}
|
||||
|
||||
-#define ANON_AND_FILE 2
|
||||
-
|
||||
enum lruvec_flags {
|
||||
LRUVEC_CONGESTED, /* lruvec has many dirty pages
|
||||
* backed by a congested BDI
|
||||
diff --git a/kernel/exit.c b/kernel/exit.c
|
||||
index 04029e35e69a..e4292717ce37 100644
|
||||
--- a/kernel/exit.c
|
||||
+++ b/kernel/exit.c
|
||||
@@ -422,6 +422,7 @@ void mm_update_next_owner(struct mm_struct *mm)
|
||||
goto retry;
|
||||
}
|
||||
WRITE_ONCE(mm->owner, c);
|
||||
+ lru_gen_migrate_mm(mm);
|
||||
task_unlock(c);
|
||||
put_task_struct(c);
|
||||
}
|
||||
diff --git a/kernel/fork.c b/kernel/fork.c
|
||||
index d3171e8e88e5..e261b797955d 100644
|
||||
--- a/kernel/fork.c
|
||||
+++ b/kernel/fork.c
|
||||
@@ -665,6 +665,7 @@ static void check_mm(struct mm_struct *mm)
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
|
||||
VM_BUG_ON_MM(mm->pmd_huge_pte, mm);
|
||||
#endif
|
||||
+ VM_BUG_ON_MM(lru_gen_mm_is_active(mm), mm);
|
||||
}
|
||||
|
||||
#define allocate_mm() (kmem_cache_alloc(mm_cachep, GFP_KERNEL))
|
||||
@@ -1047,6 +1048,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
|
||||
goto fail_nocontext;
|
||||
|
||||
mm->user_ns = get_user_ns(user_ns);
|
||||
+ lru_gen_init_mm(mm);
|
||||
return mm;
|
||||
|
||||
fail_nocontext:
|
||||
@@ -1089,6 +1091,7 @@ static inline void __mmput(struct mm_struct *mm)
|
||||
}
|
||||
if (mm->binfmt)
|
||||
module_put(mm->binfmt->module);
|
||||
+ lru_gen_del_mm(mm);
|
||||
mmdrop(mm);
|
||||
}
|
||||
|
||||
@@ -2513,6 +2516,13 @@ pid_t kernel_clone(struct kernel_clone_args *args)
|
||||
get_task_struct(p);
|
||||
}
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) {
|
||||
+ /* lock p to synchronize with memcg migration */
|
||||
+ task_lock(p);
|
||||
+ lru_gen_add_mm(p->mm);
|
||||
+ task_unlock(p);
|
||||
+ }
|
||||
+
|
||||
wake_up_new_task(p);
|
||||
|
||||
/* forking complete and child started to run, tell ptracer */
|
||||
diff --git a/kernel/kthread.c b/kernel/kthread.c
|
||||
index 1578973c5740..8da7767bb06a 100644
|
||||
--- a/kernel/kthread.c
|
||||
+++ b/kernel/kthread.c
|
||||
@@ -1303,6 +1303,7 @@ void kthread_use_mm(struct mm_struct *mm)
|
||||
tsk->mm = mm;
|
||||
membarrier_update_current_mm(mm);
|
||||
switch_mm_irqs_off(active_mm, mm, tsk);
|
||||
+ lru_gen_switch_mm(active_mm, mm);
|
||||
local_irq_enable();
|
||||
task_unlock(tsk);
|
||||
#ifdef finish_arch_post_lock_switch
|
||||
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
||||
index ca2bb629595f..56274a14ce09 100644
|
||||
--- a/kernel/sched/core.c
|
||||
+++ b/kernel/sched/core.c
|
||||
@@ -4308,6 +4308,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
|
||||
* finish_task_switch()'s mmdrop().
|
||||
*/
|
||||
switch_mm_irqs_off(prev->active_mm, next->mm, next);
|
||||
+ lru_gen_switch_mm(prev->active_mm, next->mm);
|
||||
|
||||
if (!prev->mm) { // from kernel
|
||||
/* will mmdrop() in finish_task_switch(). */
|
||||
@@ -7599,6 +7600,7 @@ void idle_task_exit(void)
|
||||
|
||||
if (mm != &init_mm) {
|
||||
switch_mm(mm, &init_mm, current);
|
||||
+ lru_gen_switch_mm(mm, &init_mm);
|
||||
finish_arch_post_lock_switch();
|
||||
}
|
||||
|
||||
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
|
||||
index 845eec01ef9d..5836780fe138 100644
|
||||
--- a/mm/memcontrol.c
|
||||
+++ b/mm/memcontrol.c
|
||||
@@ -5209,6 +5209,7 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
|
||||
free_mem_cgroup_per_node_info(memcg, node);
|
||||
free_percpu(memcg->vmstats_percpu);
|
||||
free_percpu(memcg->vmstats_local);
|
||||
+ lru_gen_free_mm_list(memcg);
|
||||
kfree(memcg);
|
||||
}
|
||||
|
||||
@@ -5261,6 +5262,9 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
|
||||
if (alloc_mem_cgroup_per_node_info(memcg, node))
|
||||
goto fail;
|
||||
|
||||
+ if (lru_gen_alloc_mm_list(memcg))
|
||||
+ goto fail;
|
||||
+
|
||||
if (memcg_wb_domain_init(memcg, GFP_KERNEL))
|
||||
goto fail;
|
||||
|
||||
@@ -6165,6 +6169,29 @@ static void mem_cgroup_move_task(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_LRU_GEN
|
||||
+static void mem_cgroup_attach(struct cgroup_taskset *tset)
|
||||
+{
|
||||
+ struct cgroup_subsys_state *css;
|
||||
+ struct task_struct *task = NULL;
|
||||
+
|
||||
+ cgroup_taskset_for_each_leader(task, css, tset)
|
||||
+ ;
|
||||
+
|
||||
+ if (!task)
|
||||
+ return;
|
||||
+
|
||||
+ task_lock(task);
|
||||
+ if (task->mm && task->mm->owner == task)
|
||||
+ lru_gen_migrate_mm(task->mm);
|
||||
+ task_unlock(task);
|
||||
+}
|
||||
+#else
|
||||
+static void mem_cgroup_attach(struct cgroup_taskset *tset)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value)
|
||||
{
|
||||
if (value == PAGE_COUNTER_MAX)
|
||||
@@ -6505,6 +6532,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
|
||||
.css_free = mem_cgroup_css_free,
|
||||
.css_reset = mem_cgroup_css_reset,
|
||||
.can_attach = mem_cgroup_can_attach,
|
||||
+ .attach = mem_cgroup_attach,
|
||||
.cancel_attach = mem_cgroup_cancel_attach,
|
||||
.post_attach = mem_cgroup_move_task,
|
||||
.dfl_cftypes = memory_files,
|
||||
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||
index 1a24d2e0a4cb..f7657ab0d4b7 100644
|
||||
--- a/mm/vmscan.c
|
||||
+++ b/mm/vmscan.c
|
||||
@@ -4314,3 +4314,266 @@ void check_move_unevictable_pages(struct pagevec *pvec)
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(check_move_unevictable_pages);
|
||||
+
|
||||
+#ifdef CONFIG_LRU_GEN
|
||||
+
|
||||
+/******************************************************************************
|
||||
+ * global and per-memcg mm list
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+/*
|
||||
+ * After pages are faulted in, they become the youngest generation. They must
|
||||
+ * go through aging process twice before they can be evicted. After first scan,
|
||||
+ * their accessed bit set during initial faults are cleared and they become the
|
||||
+ * second youngest generation. And second scan makes sure they haven't been used
|
||||
+ * since the first.
|
||||
+ */
|
||||
+#define MIN_NR_GENS 2
|
||||
+
|
||||
+static struct lru_gen_mm_list *global_mm_list;
|
||||
+
|
||||
+static struct lru_gen_mm_list *alloc_mm_list(void)
|
||||
+{
|
||||
+ int nid;
|
||||
+ struct lru_gen_mm_list *mm_list;
|
||||
+
|
||||
+ mm_list = kzalloc(struct_size(mm_list, nodes, nr_node_ids), GFP_KERNEL);
|
||||
+ if (!mm_list)
|
||||
+ return NULL;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&mm_list->head);
|
||||
+ spin_lock_init(&mm_list->lock);
|
||||
+
|
||||
+ for_each_node(nid) {
|
||||
+ mm_list->nodes[nid].cur_seq = MIN_NR_GENS - 1;
|
||||
+ mm_list->nodes[nid].iter = &mm_list->head;
|
||||
+ init_waitqueue_head(&mm_list->nodes[nid].wait);
|
||||
+ }
|
||||
+
|
||||
+ return mm_list;
|
||||
+}
|
||||
+
|
||||
+static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg)
|
||||
+{
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ if (!mem_cgroup_disabled())
|
||||
+ return memcg ? memcg->mm_list : root_mem_cgroup->mm_list;
|
||||
+#endif
|
||||
+ VM_BUG_ON(memcg);
|
||||
+
|
||||
+ return global_mm_list;
|
||||
+}
|
||||
+
|
||||
+void lru_gen_init_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+ int file;
|
||||
+
|
||||
+ INIT_LIST_HEAD(&mm->lru_gen.list);
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ mm->lru_gen.memcg = NULL;
|
||||
+#endif
|
||||
+#ifndef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
||||
+ atomic_set(&mm->lru_gen.nr_cpus, 0);
|
||||
+#endif
|
||||
+ for (file = 0; file < ANON_AND_FILE; file++)
|
||||
+ nodes_clear(mm->lru_gen.nodes[file]);
|
||||
+}
|
||||
+
|
||||
+void lru_gen_add_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm);
|
||||
+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg);
|
||||
+
|
||||
+ VM_BUG_ON_MM(!list_empty(&mm->lru_gen.list), mm);
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ VM_BUG_ON_MM(mm->lru_gen.memcg, mm);
|
||||
+ WRITE_ONCE(mm->lru_gen.memcg, memcg);
|
||||
+#endif
|
||||
+ spin_lock(&mm_list->lock);
|
||||
+ list_add_tail(&mm->lru_gen.list, &mm_list->head);
|
||||
+ spin_unlock(&mm_list->lock);
|
||||
+}
|
||||
+
|
||||
+void lru_gen_del_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+ int nid;
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ struct lru_gen_mm_list *mm_list = get_mm_list(mm->lru_gen.memcg);
|
||||
+#else
|
||||
+ struct lru_gen_mm_list *mm_list = get_mm_list(NULL);
|
||||
+#endif
|
||||
+
|
||||
+ spin_lock(&mm_list->lock);
|
||||
+
|
||||
+ for_each_node(nid) {
|
||||
+ if (mm_list->nodes[nid].iter != &mm->lru_gen.list)
|
||||
+ continue;
|
||||
+
|
||||
+ mm_list->nodes[nid].iter = mm_list->nodes[nid].iter->next;
|
||||
+ if (mm_list->nodes[nid].iter == &mm_list->head)
|
||||
+ WRITE_ONCE(mm_list->nodes[nid].cur_seq,
|
||||
+ mm_list->nodes[nid].cur_seq + 1);
|
||||
+ }
|
||||
+
|
||||
+ list_del_init(&mm->lru_gen.list);
|
||||
+
|
||||
+ spin_unlock(&mm_list->lock);
|
||||
+
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ mem_cgroup_put(mm->lru_gen.memcg);
|
||||
+ WRITE_ONCE(mm->lru_gen.memcg, NULL);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+int lru_gen_alloc_mm_list(struct mem_cgroup *memcg)
|
||||
+{
|
||||
+ if (mem_cgroup_disabled())
|
||||
+ return 0;
|
||||
+
|
||||
+ memcg->mm_list = alloc_mm_list();
|
||||
+
|
||||
+ return memcg->mm_list ? 0 : -ENOMEM;
|
||||
+}
|
||||
+
|
||||
+void lru_gen_free_mm_list(struct mem_cgroup *memcg)
|
||||
+{
|
||||
+ kfree(memcg->mm_list);
|
||||
+ memcg->mm_list = NULL;
|
||||
+}
|
||||
+
|
||||
+void lru_gen_migrate_mm(struct mm_struct *mm)
|
||||
+{
|
||||
+ struct mem_cgroup *memcg;
|
||||
+
|
||||
+ lockdep_assert_held(&mm->owner->alloc_lock);
|
||||
+
|
||||
+ if (mem_cgroup_disabled())
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ memcg = mem_cgroup_from_task(mm->owner);
|
||||
+ rcu_read_unlock();
|
||||
+ if (memcg == mm->lru_gen.memcg)
|
||||
+ return;
|
||||
+
|
||||
+ VM_BUG_ON_MM(!mm->lru_gen.memcg, mm);
|
||||
+ VM_BUG_ON_MM(list_empty(&mm->lru_gen.list), mm);
|
||||
+
|
||||
+ lru_gen_del_mm(mm);
|
||||
+ lru_gen_add_mm(mm);
|
||||
+}
|
||||
+
|
||||
+static bool mm_has_migrated(struct mm_struct *mm, struct mem_cgroup *memcg)
|
||||
+{
|
||||
+ return READ_ONCE(mm->lru_gen.memcg) != memcg;
|
||||
+}
|
||||
+#else
|
||||
+static bool mm_has_migrated(struct mm_struct *mm, struct mem_cgroup *memcg)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static bool should_skip_mm(struct mm_struct *mm, int nid, int swappiness)
|
||||
+{
|
||||
+ int file;
|
||||
+ unsigned long size = 0;
|
||||
+
|
||||
+ if (mm_is_oom_victim(mm))
|
||||
+ return true;
|
||||
+
|
||||
+ for (file = !swappiness; file < ANON_AND_FILE; file++) {
|
||||
+ if (lru_gen_mm_is_active(mm) || node_isset(nid, mm->lru_gen.nodes[file]))
|
||||
+ size += file ? get_mm_counter(mm, MM_FILEPAGES) :
|
||||
+ get_mm_counter(mm, MM_ANONPAGES) +
|
||||
+ get_mm_counter(mm, MM_SHMEMPAGES);
|
||||
+ }
|
||||
+
|
||||
+ if (size < SWAP_CLUSTER_MAX)
|
||||
+ return true;
|
||||
+
|
||||
+ return !mmget_not_zero(mm);
|
||||
+}
|
||||
+
|
||||
+/* To support multiple workers that concurrently walk mm list. */
|
||||
+static bool get_next_mm(struct lruvec *lruvec, unsigned long next_seq,
|
||||
+ int swappiness, struct mm_struct **iter)
|
||||
+{
|
||||
+ bool last = true;
|
||||
+ struct mm_struct *mm = NULL;
|
||||
+ int nid = lruvec_pgdat(lruvec)->node_id;
|
||||
+ struct mem_cgroup *memcg = lruvec_memcg(lruvec);
|
||||
+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg);
|
||||
+
|
||||
+ if (*iter)
|
||||
+ mmput_async(*iter);
|
||||
+ else if (next_seq <= READ_ONCE(mm_list->nodes[nid].cur_seq))
|
||||
+ return false;
|
||||
+
|
||||
+ spin_lock(&mm_list->lock);
|
||||
+
|
||||
+ VM_BUG_ON(next_seq > mm_list->nodes[nid].cur_seq + 1);
|
||||
+ VM_BUG_ON(*iter && next_seq < mm_list->nodes[nid].cur_seq);
|
||||
+ VM_BUG_ON(*iter && !mm_list->nodes[nid].nr_workers);
|
||||
+
|
||||
+ if (next_seq <= mm_list->nodes[nid].cur_seq) {
|
||||
+ last = *iter;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ if (mm_list->nodes[nid].iter == &mm_list->head) {
|
||||
+ VM_BUG_ON(*iter || mm_list->nodes[nid].nr_workers);
|
||||
+ mm_list->nodes[nid].iter = mm_list->nodes[nid].iter->next;
|
||||
+ }
|
||||
+
|
||||
+ while (!mm && mm_list->nodes[nid].iter != &mm_list->head) {
|
||||
+ mm = list_entry(mm_list->nodes[nid].iter, struct mm_struct, lru_gen.list);
|
||||
+ mm_list->nodes[nid].iter = mm_list->nodes[nid].iter->next;
|
||||
+ if (should_skip_mm(mm, nid, swappiness))
|
||||
+ mm = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (mm_list->nodes[nid].iter == &mm_list->head)
|
||||
+ WRITE_ONCE(mm_list->nodes[nid].cur_seq,
|
||||
+ mm_list->nodes[nid].cur_seq + 1);
|
||||
+done:
|
||||
+ if (*iter && !mm)
|
||||
+ mm_list->nodes[nid].nr_workers--;
|
||||
+ if (!*iter && mm)
|
||||
+ mm_list->nodes[nid].nr_workers++;
|
||||
+
|
||||
+ last = last && !mm_list->nodes[nid].nr_workers &&
|
||||
+ mm_list->nodes[nid].iter == &mm_list->head;
|
||||
+
|
||||
+ spin_unlock(&mm_list->lock);
|
||||
+
|
||||
+ *iter = mm;
|
||||
+
|
||||
+ return last;
|
||||
+}
|
||||
+
|
||||
+/******************************************************************************
|
||||
+ * initialization
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+static int __init init_lru_gen(void)
|
||||
+{
|
||||
+ if (mem_cgroup_disabled()) {
|
||||
+ global_mm_list = alloc_mm_list();
|
||||
+ if (!global_mm_list) {
|
||||
+ pr_err("lru_gen: failed to allocate global mm list\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+};
|
||||
+/*
|
||||
+ * We want to run as early as possible because some debug code, e.g.,
|
||||
+ * dma_resv_lockdep(), calls mm_alloc() and mmput(). We only depend on mm_kobj,
|
||||
+ * which is initialized one stage earlier by postcore_initcall().
|
||||
+ */
|
||||
+arch_initcall(init_lru_gen);
|
||||
+
|
||||
+#endif /* CONFIG_LRU_GEN */
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,612 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 898B5C432C3
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 6BE1864ECE
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233554AbhCMH6p (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:45 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59010 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232974AbhCMH6L (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:11 -0500
|
||||
Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AED49C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:11 -0800 (PST)
|
||||
Received: by mail-qt1-x84a.google.com with SMTP id b21so19336130qtr.8
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:11 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=xqbmxYHaO3cMzT5bj/KOIzl+A4iyODs6ga8GzAKSrkE=;
|
||||
b=aCMPh4sfMlM3e6I+5or6zJlbHk6bJJ366JgVLE0jRyU2R9ZqTAdl/pzm6yajVT6ycB
|
||||
R3xLH3mN1h4Agtzp3ZKjLdBAoR0i0R0R6lzXQljBVIbOuqUZFY+sw3o8WmPkGc03xc2m
|
||||
dr44s/QwksFpUKxra33PNDauwhk0aM45ZbRd238UtPStswmrshOSmIlfZiRKTC4jSk1B
|
||||
IT5xjTbNazZfQOZvoiY7Q3k+uwbArdxbxTXjz8ad9h7O5bQfF9wGt4VgjerJbWQKhTRU
|
||||
zgbLNXljWtIdgOpRYmaNN+huMS6V5KkWhB+tZ5LkJGhbn+JmFhmrfjMn35Xnhql3Eveu
|
||||
q92A==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=xqbmxYHaO3cMzT5bj/KOIzl+A4iyODs6ga8GzAKSrkE=;
|
||||
b=ELwP/ih5rcnRV8ilH4wHoagohM2fYPTmpUPvhQxKwiuGY8hsFrPo23R7PzwR30oiWI
|
||||
VctwtgGSRFQFOyfcWEPNP4SMqwwIk1eu8glqg6CQWKa87rY721qEk0JRsgjewFSqdoTI
|
||||
pKd+k+VBiLUxlIqwPjnBAqVby7cJUv4e/5BOpOxLQJJh+spTjfp7T679SBSky3ro/JqC
|
||||
EID5nP4xORL+8LLUSfsRJn1CTWks+GWRIh0JOE/gxlIb9DhVYxCv8PRv2CA2pjIrDXjk
|
||||
3nxSdtaSAsInb0PAzpAG4+NVKF1suSWoJNb8d7fOob5HfXhA0/1aBLU8JsYpZdHS3oQL
|
||||
ddhw==
|
||||
X-Gm-Message-State: AOAM5319lFA9q7zjycOKH1TFLtjK6rHjUIfzRtUZRSmbTbvpAGZvBnqr
|
||||
cx6R08ZkL0PPGp5qZ/enqEaNYC+EDX8=
|
||||
X-Google-Smtp-Source: ABdhPJx1/5VDYsBrZetaVUsn197WpRCAdLjUCneommYhd37knsedDkkTX9reu4Vy54B+q98cUeZMGTzp9xY=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:ad4:4581:: with SMTP id x1mr1753140qvu.9.1615622290851;
|
||||
Fri, 12 Mar 2021 23:58:10 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:44 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-12-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 11/14] mm: multigenerational lru: page activation
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-12-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
In the page fault path, we want to add pages to the per-zone lists
|
||||
index by max_seq as they cannot be evicted without going through
|
||||
the aging first. For anon pages, we rename
|
||||
lru_cache_add_inactive_or_unevictable() to lru_cache_add_page_vma()
|
||||
and add a new parameter, which is set to true in the page fault path,
|
||||
to indicate whether they should be added to the per-zone lists index
|
||||
by max_seq. For page/swap cache, since we cannot differentiate the
|
||||
page fault path from the read ahead path at the time we call
|
||||
lru_cache_add() in add_to_page_cache_lru() and
|
||||
__read_swap_cache_async(), we have to add a new function
|
||||
lru_gen_activate_page(), which is essentially activate_page(), to move
|
||||
pages to the per-zone lists indexed by max_seq at a later time.
|
||||
Hopefully we would find pages we want to activate in lru_pvecs.lru_add
|
||||
and simply set PageActive() on them without having to actually move
|
||||
them.
|
||||
|
||||
In the reclaim path, pages mapped around a referenced PTE may also
|
||||
have been referenced due to spatial locality. We add a new function
|
||||
lru_gen_scan_around() to scan the vicinity of such a PTE.
|
||||
|
||||
In addition, we add a new function page_is_active() to tell whether a
|
||||
page is active. We cannot use PageActive() because it is only set on
|
||||
active pages while they are not on multigenerational lru. It is
|
||||
cleared while pages are on multigenerational lru, in order to spare
|
||||
the aging the trouble of clearing it when an active generation becomes
|
||||
inactive. Internally, page_is_active() compares the generation number
|
||||
of a page with max_seq and max_seq-1, which are active generations and
|
||||
protected from the eviction. Other generations, which may or may not
|
||||
exist, are inactive.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
fs/proc/task_mmu.c | 3 ++-
|
||||
include/linux/mm_inline.h | 52 ++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mmzone.h | 6 +++++
|
||||
include/linux/swap.h | 4 +--
|
||||
kernel/events/uprobes.c | 2 +-
|
||||
mm/huge_memory.c | 2 +-
|
||||
mm/khugepaged.c | 2 +-
|
||||
mm/memory.c | 14 +++++++----
|
||||
mm/migrate.c | 2 +-
|
||||
mm/rmap.c | 6 +++++
|
||||
mm/swap.c | 26 +++++++++++--------
|
||||
mm/swapfile.c | 2 +-
|
||||
mm/userfaultfd.c | 2 +-
|
||||
mm/vmscan.c | 53 ++++++++++++++++++++++++++++++++++++++-
|
||||
14 files changed, 150 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
|
||||
index 3cec6fbef725..7cd173710e76 100644
|
||||
--- a/fs/proc/task_mmu.c
|
||||
+++ b/fs/proc/task_mmu.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/pkeys.h>
|
||||
+#include <linux/mm_inline.h>
|
||||
|
||||
#include <asm/elf.h>
|
||||
#include <asm/tlb.h>
|
||||
@@ -1720,7 +1721,7 @@ static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty,
|
||||
if (PageSwapCache(page))
|
||||
md->swapcache += nr_pages;
|
||||
|
||||
- if (PageActive(page) || PageUnevictable(page))
|
||||
+ if (PageUnevictable(page) || page_is_active(compound_head(page), NULL))
|
||||
md->active += nr_pages;
|
||||
|
||||
if (PageWriteback(page))
|
||||
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
|
||||
index 2d306cab36bc..a1a382418fc4 100644
|
||||
--- a/include/linux/mm_inline.h
|
||||
+++ b/include/linux/mm_inline.h
|
||||
@@ -116,6 +116,49 @@ static inline int page_lru_gen(struct page *page)
|
||||
return ((READ_ONCE(page->flags) & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1;
|
||||
}
|
||||
|
||||
+/* This function works regardless whether multigenerational lru is enabled. */
|
||||
+static inline bool page_is_active(struct page *page, struct lruvec *lruvec)
|
||||
+{
|
||||
+ struct mem_cgroup *memcg;
|
||||
+ int gen = page_lru_gen(page);
|
||||
+ bool active = false;
|
||||
+
|
||||
+ VM_BUG_ON_PAGE(PageTail(page), page);
|
||||
+
|
||||
+ if (gen < 0)
|
||||
+ return PageActive(page);
|
||||
+
|
||||
+ if (lruvec) {
|
||||
+ VM_BUG_ON_PAGE(PageUnevictable(page), page);
|
||||
+ VM_BUG_ON_PAGE(PageActive(page), page);
|
||||
+ lockdep_assert_held(&lruvec->lru_lock);
|
||||
+
|
||||
+ return lru_gen_is_active(lruvec, gen);
|
||||
+ }
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ memcg = page_memcg_rcu(page);
|
||||
+ lruvec = mem_cgroup_lruvec(memcg, page_pgdat(page));
|
||||
+ active = lru_gen_is_active(lruvec, gen);
|
||||
+
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return active;
|
||||
+}
|
||||
+
|
||||
+/* Activate a page from page cache or swap cache after it's mapped. */
|
||||
+static inline void lru_gen_activate_page(struct page *page, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ if (!lru_gen_enabled() || PageActive(page))
|
||||
+ return;
|
||||
+
|
||||
+ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_HUGETLB))
|
||||
+ return;
|
||||
+
|
||||
+ activate_page(page);
|
||||
+}
|
||||
+
|
||||
/* Update multigenerational lru sizes in addition to active/inactive lru sizes. */
|
||||
static inline void lru_gen_update_size(struct page *page, struct lruvec *lruvec,
|
||||
int old_gen, int new_gen)
|
||||
@@ -252,6 +295,15 @@ static inline bool lru_gen_enabled(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
+static inline bool page_is_active(struct page *page, struct lruvec *lruvec)
|
||||
+{
|
||||
+ return PageActive(page);
|
||||
+}
|
||||
+
|
||||
+static inline void lru_gen_activate_page(struct page *page, struct vm_area_struct *vma)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
static inline bool page_set_lru_gen(struct page *page, struct lruvec *lruvec, bool front)
|
||||
{
|
||||
return false;
|
||||
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
|
||||
index 173083bb846e..99156602cd06 100644
|
||||
--- a/include/linux/mmzone.h
|
||||
+++ b/include/linux/mmzone.h
|
||||
@@ -292,6 +292,7 @@ enum lruvec_flags {
|
||||
};
|
||||
|
||||
struct lruvec;
|
||||
+struct page_vma_mapped_walk;
|
||||
|
||||
#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF)
|
||||
|
||||
@@ -328,6 +329,7 @@ struct lru_gen {
|
||||
|
||||
void lru_gen_init_lruvec(struct lruvec *lruvec);
|
||||
void lru_gen_set_state(bool enable, bool main, bool swap);
|
||||
+void lru_gen_scan_around(struct page_vma_mapped_walk *pvmw);
|
||||
|
||||
#else /* CONFIG_LRU_GEN */
|
||||
|
||||
@@ -339,6 +341,10 @@ static inline void lru_gen_set_state(bool enable, bool main, bool swap)
|
||||
{
|
||||
}
|
||||
|
||||
+static inline void lru_gen_scan_around(struct page_vma_mapped_walk *pvmw)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
#endif /* CONFIG_LRU_GEN */
|
||||
|
||||
struct lruvec {
|
||||
diff --git a/include/linux/swap.h b/include/linux/swap.h
|
||||
index de2bbbf181ba..0e7532c7db22 100644
|
||||
--- a/include/linux/swap.h
|
||||
+++ b/include/linux/swap.h
|
||||
@@ -350,8 +350,8 @@ extern void deactivate_page(struct page *page);
|
||||
extern void mark_page_lazyfree(struct page *page);
|
||||
extern void swap_setup(void);
|
||||
|
||||
-extern void lru_cache_add_inactive_or_unevictable(struct page *page,
|
||||
- struct vm_area_struct *vma);
|
||||
+extern void lru_cache_add_page_vma(struct page *page, struct vm_area_struct *vma,
|
||||
+ bool faulting);
|
||||
|
||||
/* linux/mm/vmscan.c */
|
||||
extern unsigned long zone_reclaimable_pages(struct zone *zone);
|
||||
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
|
||||
index 6addc9780319..4e93e5602723 100644
|
||||
--- a/kernel/events/uprobes.c
|
||||
+++ b/kernel/events/uprobes.c
|
||||
@@ -184,7 +184,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
|
||||
if (new_page) {
|
||||
get_page(new_page);
|
||||
page_add_new_anon_rmap(new_page, vma, addr, false);
|
||||
- lru_cache_add_inactive_or_unevictable(new_page, vma);
|
||||
+ lru_cache_add_page_vma(new_page, vma, false);
|
||||
} else
|
||||
/* no new page, just dec_mm_counter for old_page */
|
||||
dec_mm_counter(mm, MM_ANONPAGES);
|
||||
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
|
||||
index be9bf681313c..62e14da5264e 100644
|
||||
--- a/mm/huge_memory.c
|
||||
+++ b/mm/huge_memory.c
|
||||
@@ -637,7 +637,7 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf,
|
||||
entry = mk_huge_pmd(page, vma->vm_page_prot);
|
||||
entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
|
||||
page_add_new_anon_rmap(page, vma, haddr, true);
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, true);
|
||||
pgtable_trans_huge_deposit(vma->vm_mm, vmf->pmd, pgtable);
|
||||
set_pmd_at(vma->vm_mm, haddr, vmf->pmd, entry);
|
||||
update_mmu_cache_pmd(vma, vmf->address, vmf->pmd);
|
||||
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
|
||||
index a7d6cb912b05..08a43910f232 100644
|
||||
--- a/mm/khugepaged.c
|
||||
+++ b/mm/khugepaged.c
|
||||
@@ -1199,7 +1199,7 @@ static void collapse_huge_page(struct mm_struct *mm,
|
||||
spin_lock(pmd_ptl);
|
||||
BUG_ON(!pmd_none(*pmd));
|
||||
page_add_new_anon_rmap(new_page, vma, address, true);
|
||||
- lru_cache_add_inactive_or_unevictable(new_page, vma);
|
||||
+ lru_cache_add_page_vma(new_page, vma, true);
|
||||
pgtable_trans_huge_deposit(mm, pmd, pgtable);
|
||||
set_pmd_at(mm, address, pmd, _pmd);
|
||||
update_mmu_cache_pmd(vma, address, pmd);
|
||||
diff --git a/mm/memory.c b/mm/memory.c
|
||||
index c8e357627318..7188607bddb9 100644
|
||||
--- a/mm/memory.c
|
||||
+++ b/mm/memory.c
|
||||
@@ -73,6 +73,7 @@
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/vmalloc.h>
|
||||
+#include <linux/mm_inline.h>
|
||||
|
||||
#include <trace/events/kmem.h>
|
||||
|
||||
@@ -845,7 +846,7 @@ copy_present_page(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma
|
||||
copy_user_highpage(new_page, page, addr, src_vma);
|
||||
__SetPageUptodate(new_page);
|
||||
page_add_new_anon_rmap(new_page, dst_vma, addr, false);
|
||||
- lru_cache_add_inactive_or_unevictable(new_page, dst_vma);
|
||||
+ lru_cache_add_page_vma(new_page, dst_vma, false);
|
||||
rss[mm_counter(new_page)]++;
|
||||
|
||||
/* All done, just insert the new page copy in the child */
|
||||
@@ -2913,7 +2914,7 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
|
||||
*/
|
||||
ptep_clear_flush_notify(vma, vmf->address, vmf->pte);
|
||||
page_add_new_anon_rmap(new_page, vma, vmf->address, false);
|
||||
- lru_cache_add_inactive_or_unevictable(new_page, vma);
|
||||
+ lru_cache_add_page_vma(new_page, vma, true);
|
||||
/*
|
||||
* We call the notify macro here because, when using secondary
|
||||
* mmu page tables (such as kvm shadow page tables), we want the
|
||||
@@ -3436,9 +3437,10 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
|
||||
/* ksm created a completely new copy */
|
||||
if (unlikely(page != swapcache && swapcache)) {
|
||||
page_add_new_anon_rmap(page, vma, vmf->address, false);
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, true);
|
||||
} else {
|
||||
do_page_add_anon_rmap(page, vma, vmf->address, exclusive);
|
||||
+ lru_gen_activate_page(page, vma);
|
||||
}
|
||||
|
||||
swap_free(entry);
|
||||
@@ -3582,7 +3584,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
|
||||
|
||||
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
|
||||
page_add_new_anon_rmap(page, vma, vmf->address, false);
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, true);
|
||||
setpte:
|
||||
set_pte_at(vma->vm_mm, vmf->address, vmf->pte, entry);
|
||||
|
||||
@@ -3707,6 +3709,7 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct page *page)
|
||||
|
||||
add_mm_counter(vma->vm_mm, mm_counter_file(page), HPAGE_PMD_NR);
|
||||
page_add_file_rmap(page, true);
|
||||
+ lru_gen_activate_page(page, vma);
|
||||
/*
|
||||
* deposit and withdraw with pmd lock held
|
||||
*/
|
||||
@@ -3750,10 +3753,11 @@ void do_set_pte(struct vm_fault *vmf, struct page *page, unsigned long addr)
|
||||
if (write && !(vma->vm_flags & VM_SHARED)) {
|
||||
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
|
||||
page_add_new_anon_rmap(page, vma, addr, false);
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, true);
|
||||
} else {
|
||||
inc_mm_counter_fast(vma->vm_mm, mm_counter_file(page));
|
||||
page_add_file_rmap(page, false);
|
||||
+ lru_gen_activate_page(page, vma);
|
||||
}
|
||||
set_pte_at(vma->vm_mm, addr, vmf->pte, entry);
|
||||
}
|
||||
diff --git a/mm/migrate.c b/mm/migrate.c
|
||||
index 62b81d5257aa..1064b03cac33 100644
|
||||
--- a/mm/migrate.c
|
||||
+++ b/mm/migrate.c
|
||||
@@ -3004,7 +3004,7 @@ static void migrate_vma_insert_page(struct migrate_vma *migrate,
|
||||
inc_mm_counter(mm, MM_ANONPAGES);
|
||||
page_add_new_anon_rmap(page, vma, addr, false);
|
||||
if (!is_zone_device_page(page))
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, false);
|
||||
get_page(page);
|
||||
|
||||
if (flush) {
|
||||
diff --git a/mm/rmap.c b/mm/rmap.c
|
||||
index b0fc27e77d6d..a44f9ee74ee1 100644
|
||||
--- a/mm/rmap.c
|
||||
+++ b/mm/rmap.c
|
||||
@@ -72,6 +72,7 @@
|
||||
#include <linux/page_idle.h>
|
||||
#include <linux/memremap.h>
|
||||
#include <linux/userfaultfd_k.h>
|
||||
+#include <linux/mm_inline.h>
|
||||
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
@@ -792,6 +793,11 @@ static bool page_referenced_one(struct page *page, struct vm_area_struct *vma,
|
||||
}
|
||||
|
||||
if (pvmw.pte) {
|
||||
+ /* multigenerational lru exploits spatial locality */
|
||||
+ if (lru_gen_enabled() && pte_young(*pvmw.pte)) {
|
||||
+ lru_gen_scan_around(&pvmw);
|
||||
+ referenced++;
|
||||
+ }
|
||||
if (ptep_clear_flush_young_notify(vma, address,
|
||||
pvmw.pte)) {
|
||||
/*
|
||||
diff --git a/mm/swap.c b/mm/swap.c
|
||||
index bd10efe00684..7aa85004b490 100644
|
||||
--- a/mm/swap.c
|
||||
+++ b/mm/swap.c
|
||||
@@ -310,7 +310,7 @@ void lru_note_cost_page(struct page *page)
|
||||
|
||||
static void __activate_page(struct page *page, struct lruvec *lruvec)
|
||||
{
|
||||
- if (!PageActive(page) && !PageUnevictable(page)) {
|
||||
+ if (!PageUnevictable(page) && !page_is_active(page, lruvec)) {
|
||||
int nr_pages = thp_nr_pages(page);
|
||||
|
||||
del_page_from_lru_list(page, lruvec);
|
||||
@@ -341,7 +341,7 @@ static bool need_activate_page_drain(int cpu)
|
||||
static void activate_page_on_lru(struct page *page)
|
||||
{
|
||||
page = compound_head(page);
|
||||
- if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
|
||||
+ if (PageLRU(page) && !PageUnevictable(page) && !page_is_active(page, NULL)) {
|
||||
struct pagevec *pvec;
|
||||
|
||||
local_lock(&lru_pvecs.lock);
|
||||
@@ -435,7 +435,7 @@ void mark_page_accessed(struct page *page)
|
||||
* this list is never rotated or maintained, so marking an
|
||||
* evictable page accessed has no effect.
|
||||
*/
|
||||
- } else if (!PageActive(page)) {
|
||||
+ } else if (!page_is_active(page, NULL)) {
|
||||
activate_page(page);
|
||||
ClearPageReferenced(page);
|
||||
workingset_activation(page);
|
||||
@@ -471,15 +471,14 @@ void lru_cache_add(struct page *page)
|
||||
EXPORT_SYMBOL(lru_cache_add);
|
||||
|
||||
/**
|
||||
- * lru_cache_add_inactive_or_unevictable
|
||||
+ * lru_cache_add_page_vma
|
||||
* @page: the page to be added to LRU
|
||||
* @vma: vma in which page is mapped for determining reclaimability
|
||||
*
|
||||
- * Place @page on the inactive or unevictable LRU list, depending on its
|
||||
- * evictability.
|
||||
+ * Place @page on an LRU list, depending on its evictability.
|
||||
*/
|
||||
-void lru_cache_add_inactive_or_unevictable(struct page *page,
|
||||
- struct vm_area_struct *vma)
|
||||
+void lru_cache_add_page_vma(struct page *page, struct vm_area_struct *vma,
|
||||
+ bool faulting)
|
||||
{
|
||||
bool unevictable;
|
||||
|
||||
@@ -496,6 +495,11 @@ void lru_cache_add_inactive_or_unevictable(struct page *page,
|
||||
__mod_zone_page_state(page_zone(page), NR_MLOCK, nr_pages);
|
||||
count_vm_events(UNEVICTABLE_PGMLOCKED, nr_pages);
|
||||
}
|
||||
+
|
||||
+ /* multigenerational lru uses PageActive() to track page faults */
|
||||
+ if (lru_gen_enabled() && !unevictable && faulting)
|
||||
+ SetPageActive(page);
|
||||
+
|
||||
lru_cache_add(page);
|
||||
}
|
||||
|
||||
@@ -522,7 +526,7 @@ void lru_cache_add_inactive_or_unevictable(struct page *page,
|
||||
*/
|
||||
static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec)
|
||||
{
|
||||
- bool active = PageActive(page);
|
||||
+ bool active = page_is_active(page, lruvec);
|
||||
int nr_pages = thp_nr_pages(page);
|
||||
|
||||
if (PageUnevictable(page))
|
||||
@@ -562,7 +566,7 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec)
|
||||
|
||||
static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec)
|
||||
{
|
||||
- if (PageActive(page) && !PageUnevictable(page)) {
|
||||
+ if (!PageUnevictable(page) && page_is_active(page, lruvec)) {
|
||||
int nr_pages = thp_nr_pages(page);
|
||||
|
||||
del_page_from_lru_list(page, lruvec);
|
||||
@@ -676,7 +680,7 @@ void deactivate_file_page(struct page *page)
|
||||
*/
|
||||
void deactivate_page(struct page *page)
|
||||
{
|
||||
- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
|
||||
+ if (PageLRU(page) && !PageUnevictable(page) && page_is_active(page, NULL)) {
|
||||
struct pagevec *pvec;
|
||||
|
||||
local_lock(&lru_pvecs.lock);
|
||||
diff --git a/mm/swapfile.c b/mm/swapfile.c
|
||||
index fe03cfeaa08f..c0956b3bde03 100644
|
||||
--- a/mm/swapfile.c
|
||||
+++ b/mm/swapfile.c
|
||||
@@ -1936,7 +1936,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
|
||||
page_add_anon_rmap(page, vma, addr, false);
|
||||
} else { /* ksm created a completely new copy */
|
||||
page_add_new_anon_rmap(page, vma, addr, false);
|
||||
- lru_cache_add_inactive_or_unevictable(page, vma);
|
||||
+ lru_cache_add_page_vma(page, vma, false);
|
||||
}
|
||||
swap_free(entry);
|
||||
out:
|
||||
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
|
||||
index 9a3d451402d7..e1d4cd3103b8 100644
|
||||
--- a/mm/userfaultfd.c
|
||||
+++ b/mm/userfaultfd.c
|
||||
@@ -123,7 +123,7 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm,
|
||||
|
||||
inc_mm_counter(dst_mm, MM_ANONPAGES);
|
||||
page_add_new_anon_rmap(page, dst_vma, dst_addr, false);
|
||||
- lru_cache_add_inactive_or_unevictable(page, dst_vma);
|
||||
+ lru_cache_add_page_vma(page, dst_vma, true);
|
||||
|
||||
set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte);
|
||||
|
||||
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||
index fd49a9a5d7f5..ce868d89dc53 100644
|
||||
--- a/mm/vmscan.c
|
||||
+++ b/mm/vmscan.c
|
||||
@@ -1876,7 +1876,7 @@ static unsigned noinline_for_stack move_pages_to_lru(struct lruvec *lruvec,
|
||||
add_page_to_lru_list(page, lruvec);
|
||||
nr_pages = thp_nr_pages(page);
|
||||
nr_moved += nr_pages;
|
||||
- if (PageActive(page))
|
||||
+ if (page_is_active(page, lruvec))
|
||||
workingset_age_nonresident(lruvec, nr_pages);
|
||||
}
|
||||
|
||||
@@ -4688,6 +4688,57 @@ static int page_update_lru_gen(struct page *page, int new_gen)
|
||||
return old_gen;
|
||||
}
|
||||
|
||||
+void lru_gen_scan_around(struct page_vma_mapped_walk *pvmw)
|
||||
+{
|
||||
+ pte_t *pte;
|
||||
+ unsigned long start, end;
|
||||
+ int old_gen, new_gen;
|
||||
+ unsigned long flags;
|
||||
+ struct lruvec *lruvec;
|
||||
+ struct mem_cgroup *memcg;
|
||||
+ struct pglist_data *pgdat = page_pgdat(pvmw->page);
|
||||
+
|
||||
+ lockdep_assert_held(pvmw->ptl);
|
||||
+ VM_BUG_ON_VMA(pvmw->address < pvmw->vma->vm_start, pvmw->vma);
|
||||
+
|
||||
+ start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start);
|
||||
+ end = pmd_addr_end(pvmw->address, pvmw->vma->vm_end);
|
||||
+ pte = pvmw->pte - ((pvmw->address - start) >> PAGE_SHIFT);
|
||||
+
|
||||
+ memcg = lock_page_memcg(pvmw->page);
|
||||
+ lruvec = lock_page_lruvec_irqsave(pvmw->page, &flags);
|
||||
+
|
||||
+ new_gen = lru_gen_from_seq(lruvec->evictable.max_seq);
|
||||
+
|
||||
+ for (; start != end; pte++, start += PAGE_SIZE) {
|
||||
+ struct page *page;
|
||||
+ unsigned long pfn = pte_pfn(*pte);
|
||||
+
|
||||
+ if (!pte_present(*pte) || !pte_young(*pte) || is_zero_pfn(pfn))
|
||||
+ continue;
|
||||
+
|
||||
+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
|
||||
+ continue;
|
||||
+
|
||||
+ page = compound_head(pte_page(*pte));
|
||||
+ if (page_to_nid(page) != pgdat->node_id)
|
||||
+ continue;
|
||||
+ if (page_memcg_rcu(page) != memcg)
|
||||
+ continue;
|
||||
+ /*
|
||||
+ * We may be holding many locks. So try to finish as fast as
|
||||
+ * possible and leave the accessed and the dirty bits to page
|
||||
+ * table walk.
|
||||
+ */
|
||||
+ old_gen = page_update_lru_gen(page, new_gen);
|
||||
+ if (old_gen >= 0 && old_gen != new_gen)
|
||||
+ lru_gen_update_size(page, lruvec, old_gen, new_gen);
|
||||
+ }
|
||||
+
|
||||
+ unlock_page_lruvec_irqrestore(lruvec, flags);
|
||||
+ unlock_page_memcg(pvmw->page);
|
||||
+}
|
||||
+
|
||||
struct mm_walk_args {
|
||||
struct mem_cgroup *memcg;
|
||||
unsigned long max_seq;
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,492 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 29E96C4321A
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 1649264ECE
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233577AbhCMH6q (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:46 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59016 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232992AbhCMH6N (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:13 -0500
|
||||
Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2926C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:12 -0800 (PST)
|
||||
Received: by mail-yb1-xb49.google.com with SMTP id b127so31851193ybc.13
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:12 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=HpM4Xhq08m+hN0lK+sEgEqrsIbbrPIT86c74gNI/u9w=;
|
||||
b=iZooLRgVq0QKt7uS3ecgWUo9C9cGTHyr/2U5sxKCS6QXN0IgrJO3PAgtZX95WUfwcs
|
||||
ZSAQR6gNrWG+wP3LmXgu+DSkMxuKFw0cNRjKklelEg68uDJJWokPALnGLPA4nMy8dmmL
|
||||
gNmywFSsTBT8s8Opdpx1NmeoX3AoH+b/8wRfOXpwgaGDC+vZ82D7uiEVDdLrnbyopU8f
|
||||
IpPsdEWG/PKjNmqr9aaxr+DYpbpcOwr48yDoUFRDhKXq2kRMLS3q9Cr2+5Aa3cOZI9gL
|
||||
a6NMw3O/GtXpPy+iDG3kH66GA3tICHTkX1Zm9PHqXzTR/dFawFQyNro80/QMStsyVm0P
|
||||
hUPA==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=HpM4Xhq08m+hN0lK+sEgEqrsIbbrPIT86c74gNI/u9w=;
|
||||
b=enhVyxFe4tZkU5M5CCcAvOq7XPOtrI0KR9T9RiANQFtlMzTvtrxKdJw8h9WJfPozxv
|
||||
DODj66oaquifIDjLTzxgHvuElCPtya1VXVDoZr/k/dHc0n6u5v10BW2bAYXIVIBtZgMb
|
||||
WwMcgh3rGt4wsE7QWUeFmRne+9VW55GHi1MtsKV2+fvK2y7UyMEoP6hy3iQbBcTxeLH0
|
||||
F684asdtadbsGGkyGN1KvT5S9l71CJFhEI6Zz6ag4NgojHVz2zN0kv4/qzQCkWhPUHNs
|
||||
Pqv8OmYBrbTHERb8vRmdpXAn8C+qWgQ5PHrVk8OOP3YB1/IBCCwYKqMe/Q7FeRocip4d
|
||||
Q5vw==
|
||||
X-Gm-Message-State: AOAM532t/+vC4rNBlDPUITq8/UGTKPQERiyG/Yu/AZbe1MTxG9Izfw1X
|
||||
ohDrQJQrlikp3FZQGyfgd8ZO5sD99kg=
|
||||
X-Google-Smtp-Source: ABdhPJyqRrRSS1bJd41QeWsraiQMIBjlJledYF/KyYHH/bW9K+768sYy2pOiqW2DerYXRlOndOy2egSD7FE=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a25:1184:: with SMTP id 126mr22571060ybr.430.1615622292183;
|
||||
Fri, 12 Mar 2021 23:58:12 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:45 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-13-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 12/14] mm: multigenerational lru: user space interface
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-13-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Add a sysfs file /sys/kernel/mm/lru_gen/enabled so user space can
|
||||
enable and disable multigenerational lru at runtime.
|
||||
|
||||
Add a sysfs file /sys/kernel/mm/lru_gen/spread so user space can
|
||||
spread pages out across multiple generations. More generations make
|
||||
the background aging more aggressive.
|
||||
|
||||
Add a debugfs file /sys/kernel/debug/lru_gen so user space can monitor
|
||||
multigenerational lru and trigger the aging and the eviction. This
|
||||
file has the following output:
|
||||
memcg memcg_id memcg_path
|
||||
node node_id
|
||||
min_gen birth_time anon_size file_size
|
||||
...
|
||||
max_gen birth_time anon_size file_size
|
||||
|
||||
Given a memcg and a node, "min_gen" is the oldest generation (number)
|
||||
and "max_gen" is the youngest. Birth time is in milliseconds. Anon and
|
||||
file sizes are in pages.
|
||||
|
||||
Write "+ memcg_id node_id gen [swappiness]" to this file to account
|
||||
referenced pages to generation "max_gen" and create next generation
|
||||
"max_gen"+1. "gen" must be equal to "max_gen" in order to avoid races.
|
||||
A swap file and a non-zero swappiness value are required to scan anon
|
||||
pages. If swapping is not desired, set vm.swappiness to 0 and
|
||||
overwrite it with a non-zero "swappiness".
|
||||
|
||||
Write "- memcg_id node_id gen [swappiness] [nr_to_reclaim]" to this
|
||||
file to evict generations less than or equal to "gen". "gen" must be
|
||||
less than "max_gen"-1 as "max_gen" and "max_gen"-1 are active
|
||||
generations and therefore protected from the eviction. "nr_to_reclaim"
|
||||
can be used to limit the number of pages to be evicted.
|
||||
|
||||
Multiple command lines are supported, so does concatenation with
|
||||
delimiters "," and ";".
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
mm/vmscan.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 334 insertions(+)
|
||||
|
||||
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
||||
index ce868d89dc53..b59b556e9587 100644
|
||||
--- a/mm/vmscan.c
|
||||
+++ b/mm/vmscan.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#include <linux/psi.h>
|
||||
#include <linux/pagewalk.h>
|
||||
#include <linux/memory.h>
|
||||
+#include <linux/debugfs.h>
|
||||
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/div64.h>
|
||||
@@ -5833,6 +5834,334 @@ lru_gen_online_mem(struct notifier_block *self, unsigned long action, void *arg)
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
+/******************************************************************************
|
||||
+ * sysfs interface
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+static ssize_t show_lru_gen_spread(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ return sprintf(buf, "%d\n", READ_ONCE(lru_gen_spread));
|
||||
+}
|
||||
+
|
||||
+static ssize_t store_lru_gen_spread(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ int spread;
|
||||
+
|
||||
+ if (kstrtoint(buf, 10, &spread) || spread >= MAX_NR_GENS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ WRITE_ONCE(lru_gen_spread, spread);
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct kobj_attribute lru_gen_spread_attr = __ATTR(
|
||||
+ spread, 0644,
|
||||
+ show_lru_gen_spread, store_lru_gen_spread
|
||||
+);
|
||||
+
|
||||
+static ssize_t show_lru_gen_enabled(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ return snprintf(buf, PAGE_SIZE, "%ld\n", lru_gen_enabled());
|
||||
+}
|
||||
+
|
||||
+static ssize_t store_lru_gen_enabled(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ int enable;
|
||||
+
|
||||
+ if (kstrtoint(buf, 10, &enable))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ lru_gen_set_state(enable, true, false);
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static struct kobj_attribute lru_gen_enabled_attr = __ATTR(
|
||||
+ enabled, 0644, show_lru_gen_enabled, store_lru_gen_enabled
|
||||
+);
|
||||
+
|
||||
+static struct attribute *lru_gen_attrs[] = {
|
||||
+ &lru_gen_spread_attr.attr,
|
||||
+ &lru_gen_enabled_attr.attr,
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+static struct attribute_group lru_gen_attr_group = {
|
||||
+ .name = "lru_gen",
|
||||
+ .attrs = lru_gen_attrs,
|
||||
+};
|
||||
+
|
||||
+/******************************************************************************
|
||||
+ * debugfs interface
|
||||
+ ******************************************************************************/
|
||||
+
|
||||
+static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos)
|
||||
+{
|
||||
+ struct mem_cgroup *memcg;
|
||||
+ loff_t nr_to_skip = *pos;
|
||||
+
|
||||
+ m->private = kzalloc(PATH_MAX, GFP_KERNEL);
|
||||
+ if (!m->private)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ memcg = mem_cgroup_iter(NULL, NULL, NULL);
|
||||
+ do {
|
||||
+ int nid;
|
||||
+
|
||||
+ for_each_node_state(nid, N_MEMORY) {
|
||||
+ if (!nr_to_skip--)
|
||||
+ return mem_cgroup_lruvec(memcg, NODE_DATA(nid));
|
||||
+ }
|
||||
+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)));
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void lru_gen_seq_stop(struct seq_file *m, void *v)
|
||||
+{
|
||||
+ if (!IS_ERR_OR_NULL(v))
|
||||
+ mem_cgroup_iter_break(NULL, lruvec_memcg(v));
|
||||
+
|
||||
+ kfree(m->private);
|
||||
+ m->private = NULL;
|
||||
+}
|
||||
+
|
||||
+static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
+{
|
||||
+ int nid = lruvec_pgdat(v)->node_id;
|
||||
+ struct mem_cgroup *memcg = lruvec_memcg(v);
|
||||
+
|
||||
+ ++*pos;
|
||||
+
|
||||
+ nid = next_memory_node(nid);
|
||||
+ if (nid == MAX_NUMNODES) {
|
||||
+ memcg = mem_cgroup_iter(NULL, memcg, NULL);
|
||||
+ if (!memcg)
|
||||
+ return NULL;
|
||||
+
|
||||
+ nid = first_memory_node;
|
||||
+ }
|
||||
+
|
||||
+ return mem_cgroup_lruvec(memcg, NODE_DATA(nid));
|
||||
+}
|
||||
+
|
||||
+static int lru_gen_seq_show(struct seq_file *m, void *v)
|
||||
+{
|
||||
+ unsigned long seq;
|
||||
+ struct lruvec *lruvec = v;
|
||||
+ int nid = lruvec_pgdat(lruvec)->node_id;
|
||||
+ struct mem_cgroup *memcg = lruvec_memcg(lruvec);
|
||||
+ DEFINE_MAX_SEQ(lruvec);
|
||||
+ DEFINE_MIN_SEQ(lruvec);
|
||||
+
|
||||
+ if (nid == first_memory_node) {
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ if (memcg)
|
||||
+ cgroup_path(memcg->css.cgroup, m->private, PATH_MAX);
|
||||
+#endif
|
||||
+ seq_printf(m, "memcg %5hu %s\n",
|
||||
+ mem_cgroup_id(memcg), (char *)m->private);
|
||||
+ }
|
||||
+
|
||||
+ seq_printf(m, " node %4d\n", nid);
|
||||
+
|
||||
+ for (seq = min(min_seq[0], min_seq[1]); seq <= max_seq; seq++) {
|
||||
+ int gen, file, zone;
|
||||
+ unsigned int msecs;
|
||||
+ long sizes[ANON_AND_FILE] = {};
|
||||
+
|
||||
+ gen = lru_gen_from_seq(seq);
|
||||
+
|
||||
+ msecs = jiffies_to_msecs(jiffies - READ_ONCE(
|
||||
+ lruvec->evictable.timestamps[gen]));
|
||||
+
|
||||
+ for_each_type_zone(file, zone)
|
||||
+ sizes[file] += READ_ONCE(
|
||||
+ lruvec->evictable.sizes[gen][file][zone]);
|
||||
+
|
||||
+ sizes[0] = max(sizes[0], 0L);
|
||||
+ sizes[1] = max(sizes[1], 0L);
|
||||
+
|
||||
+ seq_printf(m, "%11lu %9u %9lu %9lu\n",
|
||||
+ seq, msecs, sizes[0], sizes[1]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct seq_operations lru_gen_seq_ops = {
|
||||
+ .start = lru_gen_seq_start,
|
||||
+ .stop = lru_gen_seq_stop,
|
||||
+ .next = lru_gen_seq_next,
|
||||
+ .show = lru_gen_seq_show,
|
||||
+};
|
||||
+
|
||||
+static int lru_gen_debugfs_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ return seq_open(file, &lru_gen_seq_ops);
|
||||
+}
|
||||
+
|
||||
+static int advance_max_seq(struct lruvec *lruvec, unsigned long seq, int swappiness)
|
||||
+{
|
||||
+ struct scan_control sc = {
|
||||
+ .target_mem_cgroup = lruvec_memcg(lruvec),
|
||||
+ };
|
||||
+ DEFINE_MAX_SEQ(lruvec);
|
||||
+
|
||||
+ if (seq == max_seq)
|
||||
+ walk_mm_list(lruvec, max_seq, &sc, swappiness);
|
||||
+
|
||||
+ return seq > max_seq ? -EINVAL : 0;
|
||||
+}
|
||||
+
|
||||
+static int advance_min_seq(struct lruvec *lruvec, unsigned long seq, int swappiness,
|
||||
+ unsigned long nr_to_reclaim)
|
||||
+{
|
||||
+ struct blk_plug plug;
|
||||
+ int err = -EINTR;
|
||||
+ long nr_to_scan = LONG_MAX;
|
||||
+ struct scan_control sc = {
|
||||
+ .nr_to_reclaim = nr_to_reclaim,
|
||||
+ .target_mem_cgroup = lruvec_memcg(lruvec),
|
||||
+ .may_writepage = 1,
|
||||
+ .may_unmap = 1,
|
||||
+ .may_swap = 1,
|
||||
+ .reclaim_idx = MAX_NR_ZONES - 1,
|
||||
+ .gfp_mask = GFP_KERNEL,
|
||||
+ };
|
||||
+ DEFINE_MAX_SEQ(lruvec);
|
||||
+
|
||||
+ if (seq >= max_seq - 1)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ blk_start_plug(&plug);
|
||||
+
|
||||
+ while (!signal_pending(current)) {
|
||||
+ DEFINE_MIN_SEQ(lruvec);
|
||||
+
|
||||
+ if (seq < min(min_seq[!swappiness], min_seq[swappiness < 200]) ||
|
||||
+ !evict_lru_gen_pages(lruvec, &sc, swappiness, &nr_to_scan)) {
|
||||
+ err = 0;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ cond_resched();
|
||||
+ }
|
||||
+
|
||||
+ blk_finish_plug(&plug);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int advance_seq(char cmd, int memcg_id, int nid, unsigned long seq,
|
||||
+ int swappiness, unsigned long nr_to_reclaim)
|
||||
+{
|
||||
+ struct lruvec *lruvec;
|
||||
+ int err = -EINVAL;
|
||||
+ struct mem_cgroup *memcg = NULL;
|
||||
+
|
||||
+ if (!mem_cgroup_disabled()) {
|
||||
+ rcu_read_lock();
|
||||
+ memcg = mem_cgroup_from_id(memcg_id);
|
||||
+#ifdef CONFIG_MEMCG
|
||||
+ if (memcg && !css_tryget(&memcg->css))
|
||||
+ memcg = NULL;
|
||||
+#endif
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ if (!memcg)
|
||||
+ goto done;
|
||||
+ }
|
||||
+ if (memcg_id != mem_cgroup_id(memcg))
|
||||
+ goto done;
|
||||
+
|
||||
+ if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY))
|
||||
+ goto done;
|
||||
+
|
||||
+ lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(nid));
|
||||
+
|
||||
+ if (swappiness == -1)
|
||||
+ swappiness = get_swappiness(lruvec);
|
||||
+ else if (swappiness > 200U)
|
||||
+ goto done;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case '+':
|
||||
+ err = advance_max_seq(lruvec, seq, swappiness);
|
||||
+ break;
|
||||
+ case '-':
|
||||
+ err = advance_min_seq(lruvec, seq, swappiness, nr_to_reclaim);
|
||||
+ break;
|
||||
+ }
|
||||
+done:
|
||||
+ mem_cgroup_put(memcg);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static ssize_t lru_gen_debugfs_write(struct file *file, const char __user *src,
|
||||
+ size_t len, loff_t *pos)
|
||||
+{
|
||||
+ void *buf;
|
||||
+ char *cur, *next;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ buf = kvmalloc(len + 1, GFP_USER);
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (copy_from_user(buf, src, len)) {
|
||||
+ kvfree(buf);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ next = buf;
|
||||
+ next[len] = '\0';
|
||||
+
|
||||
+ while ((cur = strsep(&next, ",;\n"))) {
|
||||
+ int n;
|
||||
+ int end;
|
||||
+ char cmd;
|
||||
+ int memcg_id;
|
||||
+ int nid;
|
||||
+ unsigned long seq;
|
||||
+ int swappiness = -1;
|
||||
+ unsigned long nr_to_reclaim = -1;
|
||||
+
|
||||
+ cur = skip_spaces(cur);
|
||||
+ if (!*cur)
|
||||
+ continue;
|
||||
+
|
||||
+ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid,
|
||||
+ &seq, &end, &swappiness, &end, &nr_to_reclaim, &end);
|
||||
+ if (n < 4 || cur[end]) {
|
||||
+ err = -EINVAL;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ err = advance_seq(cmd, memcg_id, nid, seq, swappiness, nr_to_reclaim);
|
||||
+ if (err)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ kvfree(buf);
|
||||
+
|
||||
+ return err ? : len;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations lru_gen_debugfs_ops = {
|
||||
+ .open = lru_gen_debugfs_open,
|
||||
+ .read = seq_read,
|
||||
+ .write = lru_gen_debugfs_write,
|
||||
+ .llseek = seq_lseek,
|
||||
+ .release = seq_release,
|
||||
+};
|
||||
+
|
||||
/******************************************************************************
|
||||
* initialization
|
||||
******************************************************************************/
|
||||
@@ -5873,6 +6202,11 @@ static int __init init_lru_gen(void)
|
||||
if (hotplug_memory_notifier(lru_gen_online_mem, 0))
|
||||
pr_err("lru_gen: failed to subscribe hotplug notifications\n");
|
||||
|
||||
+ if (sysfs_create_group(mm_kobj, &lru_gen_attr_group))
|
||||
+ pr_err("lru_gen: failed to create sysfs group\n");
|
||||
+
|
||||
+ debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_debugfs_ops);
|
||||
+
|
||||
return 0;
|
||||
};
|
||||
/*
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,137 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 9E997C43619
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 8CDE364F1F
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233595AbhCMH6r (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:47 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59028 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S232999AbhCMH6P (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:15 -0500
|
||||
Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7BED3C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:14 -0800 (PST)
|
||||
Received: by mail-qk1-x74a.google.com with SMTP id c1so19954167qke.8
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:14 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=uE7IkUDVFpC8s1yHDZEBmC5mjUj6EJwbkUDWk669ASY=;
|
||||
b=uXhx05PdjRvuFkUcjNWapddDUcA7Q5UwyJE/THSSQbBgSLQkmn7ajsUcb7ZmUjhauR
|
||||
/jgBj7/Odh6Ngd12GetPXsZawVQtDY3F/Xog0R3yIye6citJOlL5TJ+2wwf2gcYmueuQ
|
||||
WYDJiJoxC2qvezUikRORLJGGQFEDfwGtR7lOiuTnagaswHyGlY8OAHiBnbM2NFrUlS9F
|
||||
wuwz3bRewUhC6hOmirv0YN+eR4e/S0TxFsdjMMf1mOQtK0M77IA18i0YjomUSsNcZo01
|
||||
GPjHMp59Yr0/XsqaDXOK5S+CA6611MojOlFbWTfafAQpXFIKwJXgkzUeIs9A5goZIWHY
|
||||
WCzQ==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=uE7IkUDVFpC8s1yHDZEBmC5mjUj6EJwbkUDWk669ASY=;
|
||||
b=bLNHbmZfUarHE/zKcwTOEXRDaaA3M3Wb9opsS8eMo1jlzRy67SWU0QGKWyLhaQIUuj
|
||||
jYh9cCeQdHC6qIfno1lltA2+v9qIhbWTkQq8IDWpy+DqlnHKeJ9+XXBQRQaso3znd4ai
|
||||
nPcd4O7/NtulCEnPJS2gjxYdwdJpTRn7zQmPaq7GzeKJRU9mvdhcR8zfovaRnZIIgwNw
|
||||
Ek53R7AbW1KCHAQtw9b0DwJz5OUi6Uqj50tx1chZcH3FUwhFwZUE2dqTAAbpx8adie8Y
|
||||
0NBJ8v2hnoSoCSy2gxlP1J+gN0mEx5Qn0C5zIt7OKkWf4Sh01kTSKIDwmcQsD0ghz6hu
|
||||
7qiQ==
|
||||
X-Gm-Message-State: AOAM5339O1/TQ9+FOQ9m7N+jX6OVojHsWyNTehwokZ5ewkZ6BLvWDrEp
|
||||
OjNCxrW3VzSi1/zx5w0Sch6pYeFtRCc=
|
||||
X-Google-Smtp-Source: ABdhPJz7oVSCBhnoApkNm1wW85JMl4kSXploQGL6Mdvavu7deAd9Mg85kMswIg+jCkfg3Z/h90N99XOQmFk=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a05:6214:1909:: with SMTP id
|
||||
er9mr1749542qvb.5.1615622293640; Fri, 12 Mar 2021 23:58:13 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:46 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-14-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 13/14] mm: multigenerational lru: Kconfig
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-14-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Add configuration options for multigenerational lru.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
mm/Kconfig | 29 +++++++++++++++++++++++++++++
|
||||
1 file changed, 29 insertions(+)
|
||||
|
||||
diff --git a/mm/Kconfig b/mm/Kconfig
|
||||
index 24c045b24b95..3a5bcc2d7a45 100644
|
||||
--- a/mm/Kconfig
|
||||
+++ b/mm/Kconfig
|
||||
@@ -872,4 +872,33 @@ config MAPPING_DIRTY_HELPERS
|
||||
config KMAP_LOCAL
|
||||
bool
|
||||
|
||||
+config LRU_GEN
|
||||
+ bool "Multigenerational LRU"
|
||||
+ depends on MMU
|
||||
+ help
|
||||
+ High performance multigenerational LRU to heavily overcommit workloads
|
||||
+ that are not IO bound. See Documentation/vm/multigen_lru.rst for
|
||||
+ details.
|
||||
+
|
||||
+ Warning: do not enable this option unless you plan to use it because
|
||||
+ it introduces a small per-process memory overhead.
|
||||
+
|
||||
+config NR_LRU_GENS
|
||||
+ int "Max number of generations"
|
||||
+ depends on LRU_GEN
|
||||
+ range 4 63
|
||||
+ default 7
|
||||
+ help
|
||||
+ This will use ilog2(N)+1 spare bits from page flags.
|
||||
+
|
||||
+ Warning: do not use numbers larger than necessary because each
|
||||
+ generation introduces a small per-node and per-memcg memory overhead.
|
||||
+
|
||||
+config LRU_GEN_ENABLED
|
||||
+ bool "Turn on by default"
|
||||
+ depends on LRU_GEN
|
||||
+ help
|
||||
+ The default value of /sys/kernel/mm/lru_gen/enabled is 0. This option
|
||||
+ changes it to 1.
|
||||
+
|
||||
endmenu
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
@ -1,329 +0,0 @@
|
||||
From mboxrd@z Thu Jan 1 00:00:00 1970
|
||||
Return-Path: <linux-kernel-owner@kernel.org>
|
||||
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
|
||||
aws-us-west-2-korg-lkml-1.web.codeaurora.org
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-26.3 required=3.0 tests=BAYES_00,DKIMWL_WL_MED,
|
||||
DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,
|
||||
INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,
|
||||
USER_AGENT_GIT,USER_IN_DEF_DKIM_WL autolearn=unavailable autolearn_force=no
|
||||
version=3.4.0
|
||||
Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
|
||||
by smtp.lore.kernel.org (Postfix) with ESMTP id 99A73C4360C
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
|
||||
by mail.kernel.org (Postfix) with ESMTP id 7C9EA64F1E
|
||||
for <linux-kernel@archiver.kernel.org>; Sat, 13 Mar 2021 07:59:07 +0000 (UTC)
|
||||
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
|
||||
id S233629AbhCMH6s (ORCPT <rfc822;linux-kernel@archiver.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:48 -0500
|
||||
Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59030 "EHLO
|
||||
lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
|
||||
with ESMTP id S233011AbhCMH6Q (ORCPT
|
||||
<rfc822;linux-kernel@vger.kernel.org>);
|
||||
Sat, 13 Mar 2021 02:58:16 -0500
|
||||
Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49])
|
||||
by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D3F77C061574
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:15 -0800 (PST)
|
||||
Received: by mail-yb1-xb49.google.com with SMTP id y7so31766185ybh.20
|
||||
for <linux-kernel@vger.kernel.org>; Fri, 12 Mar 2021 23:58:15 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=google.com; s=20161025;
|
||||
h=date:in-reply-to:message-id:mime-version:references:subject:from:to
|
||||
:cc;
|
||||
bh=b33M625vmeFm8iJFKYIy9IbS+yyXzJHrz2YlprWAE88=;
|
||||
b=qyBWCu6iSCz/+GOTBSyjEGx0UNh3wx8I4EpB+DGhW3FtbTsYmoVsgkJK7K9lMib92D
|
||||
8UESs064HgmPaCcFC9wummpEDT04EZB57UgnWkSzwsmT8q8yKbsLNsdnaqxDho13rxSL
|
||||
l1lhvY8XggaGyQS76caURzCZzmuuIb31yoMyJa36cSNEQIIGzS/Qm0HS9FQ4Sslqjhio
|
||||
7G+7M9RsfMDtCuFijNWCkO0VasJ5hLLwIPnUW2My7qRxlwAQoGToYUEA5ipkn9Ckz+I1
|
||||
ZZZL32LyYugyxj8DFHGhkOK2vtm0J8rqvkbb7eJOL7RwHttQzqGHotvqWMTx+tw95ZXr
|
||||
O2hQ==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:date:in-reply-to:message-id:mime-version
|
||||
:references:subject:from:to:cc;
|
||||
bh=b33M625vmeFm8iJFKYIy9IbS+yyXzJHrz2YlprWAE88=;
|
||||
b=c/gz9vPAEJyp/EJn3y5EFyXbzSo7i/3uPaPFgvAuDmTSD+ba6y1WjRuclOCOCm5zrN
|
||||
rzU2v5yfzmo6p+fXYM+C5uFH8SqC+cMK+bYnZUuNl3OwvgwL3kofqlcrnKaQQMqRRSey
|
||||
lrW47VbiLF0IySg6AM605BkxEjKxVIkdnWAS+bqXtQVym74gxHHOHwX5tGuCn/7Bs/c4
|
||||
cekamb+2vIeO+6/P0YD1ZdLO9LS1OwgxSor5cocBSXXW7J7bBLCGKAyU++NrNnahjJs1
|
||||
8ckqrHiqFC1mEWFcs+VBQ9/NCeVfcAfMGRtsMsljI5kll/myniTnSrETf49UyjrcTk87
|
||||
zwYQ==
|
||||
X-Gm-Message-State: AOAM531AI2qRYUeaR85JEsd20wl4qCSV4g5Qpav0tPw9JXRAxcdYk9S4
|
||||
AlH8Rls2BT9Ub2LGipv5Jfv5X2rI3ho=
|
||||
X-Google-Smtp-Source: ABdhPJwyYS+6AjG1nAXtEYBKUiLdJ5mAmkUQWOq9ngRJz7So3XTjiRhhO4QmZvWvkKbzXQ7oleb6ep4AFYs=
|
||||
X-Received: from yuzhao.bld.corp.google.com ([2620:15c:183:200:f931:d3e4:faa0:4f74])
|
||||
(user=yuzhao job=sendgmr) by 2002:a25:8003:: with SMTP id m3mr24313264ybk.452.1615622295044;
|
||||
Fri, 12 Mar 2021 23:58:15 -0800 (PST)
|
||||
Date: Sat, 13 Mar 2021 00:57:47 -0700
|
||||
In-Reply-To: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
Message-Id: <20210313075747.3781593-15-yuzhao@google.com>
|
||||
Mime-Version: 1.0
|
||||
References: <20210313075747.3781593-1-yuzhao@google.com>
|
||||
X-Mailer: git-send-email 2.31.0.rc2.261.g7f71774620-goog
|
||||
Subject: [PATCH v1 14/14] mm: multigenerational lru: documentation
|
||||
From: Yu Zhao <yuzhao@google.com>
|
||||
To: linux-mm@kvack.org
|
||||
Cc: Alex Shi <alex.shi@linux.alibaba.com>,
|
||||
Andrew Morton <akpm@linux-foundation.org>,
|
||||
Dave Hansen <dave.hansen@linux.intel.com>,
|
||||
Hillf Danton <hdanton@sina.com>,
|
||||
Johannes Weiner <hannes@cmpxchg.org>,
|
||||
Joonsoo Kim <iamjoonsoo.kim@lge.com>,
|
||||
Matthew Wilcox <willy@infradead.org>,
|
||||
Mel Gorman <mgorman@suse.de>, Michal Hocko <mhocko@suse.com>,
|
||||
Roman Gushchin <guro@fb.com>, Vlastimil Babka <vbabka@suse.cz>,
|
||||
Wei Yang <richard.weiyang@linux.alibaba.com>,
|
||||
Yang Shi <shy828301@gmail.com>,
|
||||
Ying Huang <ying.huang@intel.com>,
|
||||
linux-kernel@vger.kernel.org, page-reclaim@google.com,
|
||||
Yu Zhao <yuzhao@google.com>
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Precedence: bulk
|
||||
List-ID: <linux-kernel.vger.kernel.org>
|
||||
X-Mailing-List: linux-kernel@vger.kernel.org
|
||||
Archived-At: <https://lore.kernel.org/lkml/20210313075747.3781593-15-yuzhao@google.com/>
|
||||
List-Archive: <https://lore.kernel.org/lkml/>
|
||||
List-Post: <mailto:linux-kernel@vger.kernel.org>
|
||||
|
||||
Add Documentation/vm/multigen_lru.rst.
|
||||
|
||||
Signed-off-by: Yu Zhao <yuzhao@google.com>
|
||||
---
|
||||
Documentation/vm/index.rst | 1 +
|
||||
Documentation/vm/multigen_lru.rst | 210 ++++++++++++++++++++++++++++++
|
||||
2 files changed, 211 insertions(+)
|
||||
create mode 100644 Documentation/vm/multigen_lru.rst
|
||||
|
||||
diff --git a/Documentation/vm/index.rst b/Documentation/vm/index.rst
|
||||
index eff5fbd492d0..c353b3f55924 100644
|
||||
--- a/Documentation/vm/index.rst
|
||||
+++ b/Documentation/vm/index.rst
|
||||
@@ -17,6 +17,7 @@ various features of the Linux memory management
|
||||
|
||||
swap_numa
|
||||
zswap
|
||||
+ multigen_lru
|
||||
|
||||
Kernel developers MM documentation
|
||||
==================================
|
||||
diff --git a/Documentation/vm/multigen_lru.rst b/Documentation/vm/multigen_lru.rst
|
||||
new file mode 100644
|
||||
index 000000000000..fea927da2572
|
||||
--- /dev/null
|
||||
+++ b/Documentation/vm/multigen_lru.rst
|
||||
@@ -0,0 +1,210 @@
|
||||
+=====================
|
||||
+Multigenerational LRU
|
||||
+=====================
|
||||
+
|
||||
+Quick Start
|
||||
+===========
|
||||
+Build Options
|
||||
+-------------
|
||||
+:Required: Set ``CONFIG_LRU_GEN=y``.
|
||||
+
|
||||
+:Optional: Change ``CONFIG_NR_LRU_GENS`` to a number ``X`` to support
|
||||
+ a maximum of ``X`` generations.
|
||||
+
|
||||
+:Optional: Set ``CONFIG_LRU_GEN_ENABLED=y`` to turn the feature on by
|
||||
+ default.
|
||||
+
|
||||
+Runtime Options
|
||||
+---------------
|
||||
+:Required: Write ``1`` to ``/sys/kernel/mm/lru_gen/enable`` if the
|
||||
+ feature was not turned on by default.
|
||||
+
|
||||
+:Optional: Change ``/sys/kernel/mm/lru_gen/spread`` to a number ``N``
|
||||
+ to spread pages out across ``N+1`` generations. ``N`` must be less
|
||||
+ than ``X``. Larger values make the background aging more aggressive.
|
||||
+
|
||||
+:Optional: Read ``/sys/kernel/debug/lru_gen`` to verify the feature.
|
||||
+ This file has the following output:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ memcg memcg_id memcg_path
|
||||
+ node node_id
|
||||
+ min_gen birth_time anon_size file_size
|
||||
+ ...
|
||||
+ max_gen birth_time anon_size file_size
|
||||
+
|
||||
+Given a memcg and a node, ``min_gen`` is the oldest generation
|
||||
+(number) and ``max_gen`` is the youngest. Birth time is in
|
||||
+milliseconds. Anon and file sizes are in pages.
|
||||
+
|
||||
+Recipes
|
||||
+-------
|
||||
+:Android on ARMv8.1+: ``X=4``, ``N=0``
|
||||
+
|
||||
+:Android on pre-ARMv8.1 CPUs: Not recommended due to the lack of
|
||||
+ ``ARM64_HW_AFDBM``
|
||||
+
|
||||
+:Laptops running Chrome on x86_64: ``X=7``, ``N=2``
|
||||
+
|
||||
+:Working set estimation: Write ``+ memcg_id node_id gen [swappiness]``
|
||||
+ to ``/sys/kernel/debug/lru_gen`` to account referenced pages to
|
||||
+ generation ``max_gen`` and create the next generation ``max_gen+1``.
|
||||
+ ``gen`` must be equal to ``max_gen`` in order to avoid races. A swap
|
||||
+ file and a non-zero swappiness value are required to scan anon pages.
|
||||
+ If swapping is not desired, set ``vm.swappiness`` to ``0`` and
|
||||
+ overwrite it with a non-zero ``swappiness``.
|
||||
+
|
||||
+:Proactive reclaim: Write ``- memcg_id node_id gen [swappiness]
|
||||
+ [nr_to_reclaim]`` to ``/sys/kernel/debug/lru_gen`` to evict
|
||||
+ generations less than or equal to ``gen``. ``gen`` must be less than
|
||||
+ ``max_gen-1`` as ``max_gen`` and ``max_gen-1`` are active generations
|
||||
+ and therefore protected from the eviction. ``nr_to_reclaim`` can be
|
||||
+ used to limit the number of pages to be evicted. Multiple command
|
||||
+ lines are supported, so does concatenation with delimiters ``,`` and
|
||||
+ ``;``.
|
||||
+
|
||||
+Workflow
|
||||
+========
|
||||
+Evictable pages are divided into multiple generations for each
|
||||
+``lruvec``. The youngest generation number is stored in ``max_seq``
|
||||
+for both anon and file types as they are aged on an equal footing. The
|
||||
+oldest generation numbers are stored in ``min_seq[2]`` separately for
|
||||
+anon and file types as clean file pages can be evicted regardless of
|
||||
+swap and write-back constraints. Generation numbers are truncated into
|
||||
+``ilog2(CONFIG_NR_LRU_GENS)+1`` bits in order to fit into
|
||||
+``page->flags``. The sliding window technique is used to prevent
|
||||
+truncated generation numbers from overlapping. Each truncated
|
||||
+generation number is an index to an array of per-type and per-zone
|
||||
+lists. Evictable pages are added to the per-zone lists indexed by
|
||||
+``max_seq`` or ``min_seq[2]`` (modulo ``CONFIG_NR_LRU_GENS``),
|
||||
+depending on whether they are being faulted in or read ahead. The
|
||||
+workflow comprises two conceptually independent functions: the aging
|
||||
+and the eviction.
|
||||
+
|
||||
+Aging
|
||||
+-----
|
||||
+The aging produces young generations. Given an ``lruvec``, the aging
|
||||
+scans page tables for referenced pages of this ``lruvec``. Upon
|
||||
+finding one, the aging updates its generation number to ``max_seq``.
|
||||
+After each round of scan, the aging increments ``max_seq``. The aging
|
||||
+maintains either a system-wide ``mm_struct`` list or per-memcg
|
||||
+``mm_struct`` lists, and it only scans page tables of processes that
|
||||
+have been scheduled since the last scan. Since scans are differential
|
||||
+with respect to referenced pages, the cost is roughly proportional to
|
||||
+their number.
|
||||
+
|
||||
+Eviction
|
||||
+--------
|
||||
+The eviction consumes old generations. Given an ``lruvec``, the
|
||||
+eviction scans the pages on the per-zone lists indexed by either of
|
||||
+``min_seq[2]``. It selects a type according to the values of
|
||||
+``min_seq[2]`` and swappiness. During a scan, the eviction either
|
||||
+sorts or isolates a page, depending on whether the aging has updated
|
||||
+its generation number. When it finds all the per-zone lists are empty,
|
||||
+the eviction increments ``min_seq[2]`` indexed by this selected type.
|
||||
+The eviction triggers the aging when both of ``min_seq[2]`` reaches
|
||||
+``max_seq-1``, assuming both anon and file types are reclaimable.
|
||||
+
|
||||
+Rationale
|
||||
+=========
|
||||
+Characteristics of cloud workloads
|
||||
+----------------------------------
|
||||
+With cloud storage gone mainstream, the role of local storage has
|
||||
+diminished. For most of the systems running cloud workloads, anon
|
||||
+pages account for the majority of memory consumption and page cache
|
||||
+contains mostly executable pages. Notably, the portion of the unmapped
|
||||
+is negligible.
|
||||
+
|
||||
+As a result, swapping is necessary to achieve substantial memory
|
||||
+overcommit. And the ``rmap`` is the hottest in the reclaim path
|
||||
+because its usage is proportional to the number of scanned pages,
|
||||
+which on average is many times the number of reclaimed pages.
|
||||
+
|
||||
+With ``zram``, a typical ``kswapd`` profile on v5.11 looks like:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ 31.03% page_vma_mapped_walk
|
||||
+ 25.59% lzo1x_1_do_compress
|
||||
+ 4.63% do_raw_spin_lock
|
||||
+ 3.89% vma_interval_tree_iter_next
|
||||
+ 3.33% vma_interval_tree_subtree_search
|
||||
+
|
||||
+And with real swap, it looks like:
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ 45.16% page_vma_mapped_walk
|
||||
+ 7.61% do_raw_spin_lock
|
||||
+ 5.69% vma_interval_tree_iter_next
|
||||
+ 4.91% vma_interval_tree_subtree_search
|
||||
+ 3.71% page_referenced_one
|
||||
+
|
||||
+Limitations of the Current Implementation
|
||||
+-----------------------------------------
|
||||
+Notion of the Active/Inactive
|
||||
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
+For servers equipped with hundreds of gigabytes of memory, the
|
||||
+granularity of the active/inactive is too coarse to be useful for job
|
||||
+scheduling. And false active/inactive rates are relatively high.
|
||||
+
|
||||
+For phones and laptops, the eviction is biased toward file pages
|
||||
+because the selection has to resort to heuristics as direct
|
||||
+comparisons between anon and file types are infeasible.
|
||||
+
|
||||
+For systems with multiple nodes and/or memcgs, it is impossible to
|
||||
+compare ``lruvec``\s based on the notion of the active/inactive.
|
||||
+
|
||||
+Incremental Scans via the ``rmap``
|
||||
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
+Each incremental scan picks up at where the last scan left off and
|
||||
+stops after it has found a handful of unreferenced pages. For most of
|
||||
+the systems running cloud workloads, incremental scans lose the
|
||||
+advantage under sustained memory pressure due to high ratios of the
|
||||
+number of scanned pages to the number of reclaimed pages. On top of
|
||||
+that, the ``rmap`` has poor memory locality due to its complex data
|
||||
+structures. The combined effects typically result in a high amount of
|
||||
+CPU usage in the reclaim path.
|
||||
+
|
||||
+Benefits of the Multigenerational LRU
|
||||
+-------------------------------------
|
||||
+Notion of Generation Numbers
|
||||
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
+The notion of generation numbers introduces a quantitative approach to
|
||||
+memory overcommit. A larger number of pages can be spread out across
|
||||
+configurable generations, and thus they have relatively low false
|
||||
+active/inactive rates. Each generation includes all pages that have
|
||||
+been referenced since the last generation.
|
||||
+
|
||||
+Given an ``lruvec``, scans and the selections between anon and file
|
||||
+types are all based on generation numbers, which are simple and yet
|
||||
+effective. For different ``lruvec``\s, comparisons are still possible
|
||||
+based on birth times of generations.
|
||||
+
|
||||
+Differential Scans via Page Tables
|
||||
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
+Each differential scan discovers all pages that have been referenced
|
||||
+since the last scan. Specifically, it walks the ``mm_struct`` list
|
||||
+associated with an ``lruvec`` to scan page tables of processes that
|
||||
+have been scheduled since the last scan. The cost of each differential
|
||||
+scan is roughly proportional to the number of referenced pages it
|
||||
+discovers. Unless address spaces are extremely sparse, page tables
|
||||
+usually have better memory locality than the ``rmap``. The end result
|
||||
+is generally a significant reduction in CPU usage, for most of the
|
||||
+systems running cloud workloads.
|
||||
+
|
||||
+To-do List
|
||||
+==========
|
||||
+KVM Optimization
|
||||
+----------------
|
||||
+Support shadow page table walk.
|
||||
+
|
||||
+NUMA Optimization
|
||||
+-----------------
|
||||
+Add per-node RSS for ``should_skip_mm()``.
|
||||
+
|
||||
+Refault Tracking Optimization
|
||||
+-----------------------------
|
||||
+Use generation numbers rather than LRU positions in
|
||||
+``workingset_eviction()`` and ``workingset_refault()``.
|
||||
--
|
||||
2.31.0.rc2.261.g7f71774620-goog
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,30 +0,0 @@
|
||||
From 298c18c5bdc5f1ff302e6c83d642a7ce6307c921 Mon Sep 17 00:00:00 2001
|
||||
From: Martijn Braam <martijn@brixit.nl>
|
||||
Date: Fri, 4 Sep 2020 17:35:39 +0200
|
||||
Subject: [PATCH] media: gc2145: Added BGGR bayer mode
|
||||
|
||||
Not all raw bayer modes from the sensor match up with the ones defined
|
||||
in v4l, mostly because they're mirrored.
|
||||
---
|
||||
drivers/media/i2c/gc2145.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c
|
||||
index 40a50ee17fd3..bed611045de9 100644
|
||||
--- a/drivers/media/i2c/gc2145.c
|
||||
+++ b/drivers/media/i2c/gc2145.c
|
||||
@@ -187,6 +187,11 @@ static const struct gc2145_pixfmt gc2145_formats[] = {
|
||||
.colorspace = V4L2_COLORSPACE_SRGB,
|
||||
.fmt_setup = 0x06,
|
||||
},
|
||||
+ {
|
||||
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
|
||||
+ .colorspace = V4L2_COLORSPACE_RAW,
|
||||
+ .fmt_setup = 0x17,
|
||||
+ },
|
||||
};
|
||||
|
||||
static const struct gc2145_pixfmt *gc2145_find_format(u32 code)
|
||||
--
|
||||
GitLab
|
||||
|
@ -1,390 +0,0 @@
|
||||
From c2ea6ff2636e4e2bc88244c57197318b3d9d806b Mon Sep 17 00:00:00 2001
|
||||
From: Martijn Braam <martijn@brixit.nl>
|
||||
Date: Mon, 28 Sep 2020 14:26:11 +0200
|
||||
Subject: [PATCH] media: ov5640: Implement autofocus
|
||||
|
||||
The autofocus functionality needs a firmware blob loaded into the
|
||||
internal microcontroller.
|
||||
|
||||
V4L2 doesn't have an api to control all autofocus functionality, but
|
||||
this at least makes it possible to focus on the center of the sensor.
|
||||
|
||||
Signed-off-by: Martijn Braam <martijn@brixit.nl>
|
||||
---
|
||||
drivers/media/i2c/ov5640.c | 254 +++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 254 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
|
||||
index 16ecde24a192..d90fc35e8503 100644
|
||||
--- a/drivers/media/i2c/ov5640.c
|
||||
+++ b/drivers/media/i2c/ov5640.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/firmware.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -31,7 +32,11 @@
|
||||
|
||||
#define OV5640_DEFAULT_SLAVE_ID 0x3c
|
||||
|
||||
+#define OV5640_REG_SYS_RESET00 0x3000
|
||||
+#define OV5640_REG_SYS_RESET01 0x3001
|
||||
#define OV5640_REG_SYS_RESET02 0x3002
|
||||
+#define OV5640_REG_SYS_CLOCK_ENABLE00 0x3004
|
||||
+#define OV5640_REG_SYS_CLOCK_ENABLE01 0x3005
|
||||
#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
|
||||
#define OV5640_REG_SYS_CTRL0 0x3008
|
||||
#define OV5640_REG_CHIP_ID 0x300a
|
||||
@@ -39,6 +44,14 @@
|
||||
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
|
||||
#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018
|
||||
#define OV5640_REG_PAD_OUTPUT00 0x3019
|
||||
+#define OV5640_REG_FW_CMD_MAIN 0x3022
|
||||
+#define OV5640_REG_FW_CMD_ACK 0x3023
|
||||
+#define OV5640_REG_FW_CMD_PARA0 0x3024
|
||||
+#define OV5640_REG_FW_CMD_PARA1 0x3025
|
||||
+#define OV5640_REG_FW_CMD_PARA2 0x3026
|
||||
+#define OV5640_REG_FW_CMD_PARA3 0x3027
|
||||
+#define OV5640_REG_FW_CMD_PARA4 0x3028
|
||||
+#define OV5640_REG_FW_STATUS 0x3029
|
||||
#define OV5640_REG_SYSTEM_CONTROL1 0x302e
|
||||
#define OV5640_REG_SC_PLL_CTRL0 0x3034
|
||||
#define OV5640_REG_SC_PLL_CTRL1 0x3035
|
||||
@@ -57,6 +70,7 @@
|
||||
#define OV5640_REG_AEC_PK_MANUAL 0x3503
|
||||
#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
|
||||
#define OV5640_REG_AEC_PK_VTS 0x350c
|
||||
+#define OV5640_REG_VCM_CONTROL4 0x3606
|
||||
#define OV5640_REG_TIMING_DVPHO 0x3808
|
||||
#define OV5640_REG_TIMING_DVPVO 0x380a
|
||||
#define OV5640_REG_TIMING_HTS 0x380c
|
||||
@@ -93,6 +107,20 @@
|
||||
#define OV5640_REG_SDE_CTRL4 0x5584
|
||||
#define OV5640_REG_SDE_CTRL5 0x5585
|
||||
#define OV5640_REG_AVG_READOUT 0x56a1
|
||||
+#define OV5640_REG_FIRMWARE_BASE 0x8000
|
||||
+
|
||||
+#define OV5640_FW_STATUS_S_FIRMWARE 0x7f
|
||||
+#define OV5640_FW_STATUS_S_STARTUP 0x7e
|
||||
+#define OV5640_FW_STATUS_S_IDLE 0x70
|
||||
+#define OV5640_FW_STATUS_S_FOCUSING 0x00
|
||||
+#define OV5640_FW_STATUS_S_FOCUSED 0x10
|
||||
+
|
||||
+#define OV5640_FW_CMD_TRIGGER_FOCUS 0x03
|
||||
+#define OV5640_FW_CMD_CONTINUOUS_FOCUS 0x04
|
||||
+#define OV5640_FW_CMD_GET_FOCUS_RESULT 0x07
|
||||
+#define OV5640_FW_CMD_RELEASE_FOCUS 0x08
|
||||
+#define OV5640_FW_CMD_ZONE_CONFIG 0x12
|
||||
+#define OV5640_FW_CMD_DEFAULT_ZONES 0x80
|
||||
|
||||
enum ov5640_mode_id {
|
||||
OV5640_MODE_QCIF_176_144 = 0,
|
||||
@@ -216,6 +244,12 @@ struct ov5640_ctrls {
|
||||
struct v4l2_ctrl *auto_gain;
|
||||
struct v4l2_ctrl *gain;
|
||||
};
|
||||
+ struct {
|
||||
+ struct v4l2_ctrl *focus_auto;
|
||||
+ struct v4l2_ctrl *af_start;
|
||||
+ struct v4l2_ctrl *af_stop;
|
||||
+ struct v4l2_ctrl *af_status;
|
||||
+ };
|
||||
struct v4l2_ctrl *brightness;
|
||||
struct v4l2_ctrl *light_freq;
|
||||
struct v4l2_ctrl *saturation;
|
||||
@@ -259,6 +293,8 @@ struct ov5640_dev {
|
||||
|
||||
bool pending_mode_change;
|
||||
bool streaming;
|
||||
+
|
||||
+ bool af_initialized;
|
||||
};
|
||||
|
||||
static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
|
||||
@@ -1982,6 +2018,99 @@ static void ov5640_reset(struct ov5640_dev *sensor)
|
||||
usleep_range(20000, 25000);
|
||||
}
|
||||
|
||||
+static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor,
|
||||
+ const struct firmware *fw)
|
||||
+{
|
||||
+ struct i2c_client *client = sensor->i2c_client;
|
||||
+ const u8 *data = (const u8 *)fw->data;
|
||||
+ u8 fw_status;
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ // Putting MCU in reset state
|
||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ // Write firmware
|
||||
+ for (i = 0; i < fw->size / sizeof(u8); i++)
|
||||
+ ov5640_write_reg(sensor,
|
||||
+ OV5640_REG_FIRMWARE_BASE + i,
|
||||
+ data[i]);
|
||||
+
|
||||
+ // Reset MCU state
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA0, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA1, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA2, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA3, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA4, 0x00);
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_FW_STATUS, 0x7f);
|
||||
+
|
||||
+ // Start AF MCU
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ dev_info(&client->dev, "firmware upload success\n");
|
||||
+
|
||||
+ // Wait for firmware to be ready
|
||||
+ for (i = 0; i < 100; i++) {
|
||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
|
||||
+ if (fw_status == OV5640_FW_STATUS_S_IDLE) {
|
||||
+ dev_info(&client->dev, "fw started after %d ms\n", i * 50);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ msleep(50);
|
||||
+ }
|
||||
+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x\n", fw_status);
|
||||
+ return -ETIMEDOUT;
|
||||
+}
|
||||
+
|
||||
+static int ov5640_af_init(struct ov5640_dev *sensor)
|
||||
+{
|
||||
+ struct i2c_client *client = sensor->i2c_client;
|
||||
+ const char* fwname = "ov5640_af.bin";
|
||||
+ const struct firmware *fw;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (sensor->af_initialized) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (firmware_request_nowarn(&fw, fwname, &client->dev) == 0) {
|
||||
+ ret = ov5640_copy_fw_to_device(sensor, fw);
|
||||
+ if (ret == 0)
|
||||
+ sensor->af_initialized = 1;
|
||||
+ } else {
|
||||
+ dev_warn(&client->dev, "%s: no autofocus firmware available (%s)\n",
|
||||
+ __func__, fwname);
|
||||
+ ret = -1;
|
||||
+ }
|
||||
+ release_firmware(fw);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ // Enable AF systems
|
||||
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE00,
|
||||
+ (BIT(6) | BIT(5)), (BIT(6) | BIT(5)));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE01,
|
||||
+ BIT(6), BIT(6));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ // Set lens focus driver on
|
||||
+ ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
||||
{
|
||||
struct i2c_client *client = sensor->i2c_client;
|
||||
@@ -2003,6 +2132,8 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
|
||||
goto xclk_off;
|
||||
}
|
||||
|
||||
+ sensor->af_initialized = 0;
|
||||
+
|
||||
ov5640_reset(sensor);
|
||||
ov5640_power(sensor, true);
|
||||
|
||||
@@ -2392,6 +2523,35 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
|
||||
is_jpeg ? (BIT(5) | BIT(3)) : 0);
|
||||
}
|
||||
|
||||
+static int ov5640_fw_command(struct ov5640_dev *sensor, int command)
|
||||
+{
|
||||
+ u8 fw_ack;
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x01);
|
||||
+ if(ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, command);
|
||||
+ if(ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ for (i = 0; i < 100; i++) {
|
||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_CMD_ACK, &fw_ack);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (fw_ack == 0){
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ msleep(50);
|
||||
+ }
|
||||
+ return -ETIMEDOUT;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Sensor Controls.
|
||||
*/
|
||||
@@ -2508,6 +2668,41 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int ov5640_set_ctrl_focus(struct ov5640_dev *sensor, int command)
|
||||
+{
|
||||
+ struct i2c_client *client = sensor->i2c_client;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = ov5640_af_init(sensor);
|
||||
+ if (ret) {
|
||||
+ dev_err(&client->dev, "%s: no autofocus firmware loaded\n",
|
||||
+ __func__);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (command == OV5640_FW_CMD_RELEASE_FOCUS) {
|
||||
+ dev_dbg(&client->dev, "%s: Releasing autofocus\n",
|
||||
+ __func__);
|
||||
+ return ov5640_fw_command(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
||||
+ }
|
||||
+
|
||||
+ // Restart zone config
|
||||
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_ZONE_CONFIG);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ // Set default focus zones
|
||||
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_DEFAULT_ZONES);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ dev_dbg(&client->dev, "%s: Triggering autofocus\n",
|
||||
+ __func__);
|
||||
+
|
||||
+ // Start focussing
|
||||
+ return ov5640_fw_command(sensor, command);
|
||||
+}
|
||||
+
|
||||
static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
|
||||
{
|
||||
struct ov5640_ctrls *ctrls = &sensor->ctrls;
|
||||
@@ -2614,6 +2809,32 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
|
||||
(BIT(2) | BIT(1)) : 0);
|
||||
}
|
||||
|
||||
+static int ov5640_get_af_status(struct ov5640_dev *sensor)
|
||||
+{
|
||||
+ u8 fw_status;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ switch (fw_status) {
|
||||
+ case OV5640_FW_STATUS_S_FIRMWARE:
|
||||
+ case OV5640_FW_STATUS_S_STARTUP:
|
||||
+ return V4L2_AUTO_FOCUS_STATUS_FAILED;
|
||||
+ break;
|
||||
+ case OV5640_FW_STATUS_S_IDLE:
|
||||
+ return V4L2_AUTO_FOCUS_STATUS_IDLE;
|
||||
+ break;
|
||||
+ case OV5640_FW_STATUS_S_FOCUSED:
|
||||
+ return V4L2_AUTO_FOCUS_STATUS_REACHED;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return V4L2_AUTO_FOCUS_STATUS_BUSY;
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
|
||||
@@ -2635,6 +2856,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
||||
return val;
|
||||
sensor->ctrls.exposure->val = val;
|
||||
break;
|
||||
+ case V4L2_CID_FOCUS_AUTO:
|
||||
+ val = ov5640_get_af_status(sensor);
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+ sensor->ctrls.af_status->val = val;
|
||||
+ break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2666,6 +2893,18 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
||||
ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
|
||||
break;
|
||||
+ case V4L2_CID_FOCUS_AUTO:
|
||||
+ if (ctrl->val)
|
||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_CONTINUOUS_FOCUS);
|
||||
+ else
|
||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
||||
+ break;
|
||||
+ case V4L2_CID_AUTO_FOCUS_START:
|
||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_TRIGGER_FOCUS);
|
||||
+ break;
|
||||
+ case V4L2_CID_AUTO_FOCUS_STOP:
|
||||
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
|
||||
+ break;
|
||||
case V4L2_CID_HUE:
|
||||
ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
|
||||
break;
|
||||
@@ -2738,6 +2977,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
|
||||
ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
|
||||
0, 1023, 1, 0);
|
||||
|
||||
+ /* Autofocus */
|
||||
+ ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_AUTO,
|
||||
+ 0, 1, 1, 0);
|
||||
+ ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_START,
|
||||
+ 0, 1, 1, 0);
|
||||
+ ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_STOP,
|
||||
+ 0, 1, 1, 0);
|
||||
+ ctrls->af_status = v4l2_ctrl_new_std(hdl, ops,
|
||||
+ V4L2_CID_AUTO_FOCUS_STATUS, 0,
|
||||
+ (V4L2_AUTO_FOCUS_STATUS_BUSY |
|
||||
+ V4L2_AUTO_FOCUS_STATUS_REACHED |
|
||||
+ V4L2_AUTO_FOCUS_STATUS_FAILED),
|
||||
+ 0, V4L2_AUTO_FOCUS_STATUS_IDLE);
|
||||
+
|
||||
ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
|
||||
0, 255, 1, 64);
|
||||
ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
|
||||
@@ -2771,6 +3024,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
|
||||
v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
|
||||
v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
|
||||
v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
|
||||
+ v4l2_ctrl_cluster(4, &ctrls->focus_auto);
|
||||
|
||||
sensor->sd.ctrl_handler = hdl;
|
||||
return 0;
|
||||
--
|
||||
GitLab
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
# load kernel modules that's needed to run accelarated osk SDL
|
||||
force_drivers+=" lima gpu_sched goodix evdev sun6i_mipi_dsi sun8i-drm-hdmi sun8i-mixer panel-sitronix-st7703 "
|
||||
# pmic
|
||||
force_drivers+=" axp20x-pek axp20x_adc "
|
||||
# force feedback
|
||||
force_drivers+=" gpio-vibra "
|
||||
# encryption module
|
||||
force_drivers+=" crc-t10dif "
|
||||
# emmc/sd driver
|
||||
force_drivers+=" sunxi-mmc "
|
@ -1,280 +0,0 @@
|
||||
From patchwork Sat Feb 22 02:42:10 2020
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Patchwork-Submitter: Qiang Yu <yuq825@gmail.com>
|
||||
X-Patchwork-Id: 11397805
|
||||
Return-Path: <SRS0=2VhQ=4K=lists.freedesktop.org=dri-devel-bounces@kernel.org>
|
||||
Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org
|
||||
[172.30.200.123])
|
||||
by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AB9901395
|
||||
for <patchwork-dri-devel@patchwork.kernel.org>;
|
||||
Sat, 22 Feb 2020 02:43:37 +0000 (UTC)
|
||||
Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177])
|
||||
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
|
||||
(No client certificate requested)
|
||||
by mail.kernel.org (Postfix) with ESMTPS id 88DCB20722
|
||||
for <patchwork-dri-devel@patchwork.kernel.org>;
|
||||
Sat, 22 Feb 2020 02:43:37 +0000 (UTC)
|
||||
Authentication-Results: mail.kernel.org;
|
||||
dkim=fail reason="signature verification failed" (2048-bit key)
|
||||
header.d=gmail.com header.i=@gmail.com header.b="CyObTePI"
|
||||
DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 88DCB20722
|
||||
Authentication-Results: mail.kernel.org;
|
||||
dmarc=fail (p=none dis=none) header.from=gmail.com
|
||||
Authentication-Results: mail.kernel.org;
|
||||
spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org
|
||||
Received: from gabe.freedesktop.org (localhost [127.0.0.1])
|
||||
by gabe.freedesktop.org (Postfix) with ESMTP id B7A676F5BC;
|
||||
Sat, 22 Feb 2020 02:43:36 +0000 (UTC)
|
||||
X-Original-To: dri-devel@lists.freedesktop.org
|
||||
Delivered-To: dri-devel@lists.freedesktop.org
|
||||
Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com
|
||||
[IPv6:2607:f8b0:4864:20::443])
|
||||
by gabe.freedesktop.org (Postfix) with ESMTPS id 2FC626F5C4;
|
||||
Sat, 22 Feb 2020 02:43:33 +0000 (UTC)
|
||||
Received: by mail-pf1-x443.google.com with SMTP id b185so2253361pfb.7;
|
||||
Fri, 21 Feb 2020 18:43:33 -0800 (PST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
|
||||
h=from:to:cc:subject:date:message-id:in-reply-to:references;
|
||||
bh=zmu9+9eRFyNY15h9Ek3Z+76nUFKQGmj+zanQeEr6WEg=;
|
||||
b=CyObTePIC42njRlTMpIZ5jbV07vgmVzwQlIiClf8yxmuRae7p5rmPK3RHoGWUE6mkk
|
||||
UzllkCHvhzvt7xJeIXgotAX4N0urh0fusNlyXvE7soJ3jqUTaD2H3TvbAM0MRJq7UDUK
|
||||
AaNJLBmXC2yJo03J1uSp6YEyYbywQiMhQzFK79fByFG5hWbs376E1Wy3Qr0oQizMIxph
|
||||
R7MjdGqFOb3hoejatRsG9B+ZrhD5tsUWUOzAWgFoNNgROmPyzO6RSdqRf+R51mRMg2+Q
|
||||
7CG+ZMuNBgUyKNliZ2Z6qM/WB8h6d4zd5yyCRoQtealQsMcxy3ERJkGSa+XzXACOw1bW
|
||||
HiqA==
|
||||
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
|
||||
d=1e100.net; s=20161025;
|
||||
h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
|
||||
:references;
|
||||
bh=zmu9+9eRFyNY15h9Ek3Z+76nUFKQGmj+zanQeEr6WEg=;
|
||||
b=SfIr8M5GIeETLcx/eWSJyGbZ97nYp9ucP4ZU6+QDVR67yOJvyK9xQ19orX0oLL4JzM
|
||||
sJu1kScGzfwMEmcKreQfO9W/M48PzEGuQbf4jPMFFslFKsxJYHYU0g8vJvCfmSFRc+uI
|
||||
CyBxeIgtwDfIMm8YFcqe16BwuPHqYZf3UNxPPOLJEd36t6VkBMRMjedSvCrzo3Z9vGgI
|
||||
/enU6NAeoiBdJGaRIV996k7frtHuIHCQYmhuQMl2c6kSfq/8YJDuwhQF5JyBKPpmsbun
|
||||
enEzl2SHAxR4US54RlWxvFJkoJqW3i6VoRHc7NhqjAscitShyKvjM3MkMZj85mC4DOXg
|
||||
+Uew==
|
||||
X-Gm-Message-State: APjAAAVeIOlNq5GJmxoyR4KHXrichrK35qwKJM0c31ZKqdCZpidHIHv2
|
||||
Fs9QJulvy/h7w2ta39NPizPVh8dbDyMxTA==
|
||||
X-Google-Smtp-Source:
|
||||
APXvYqwdgtryziiyB3qwd3ITAq/0Lqdj/vlMbD6j/DyX5dGHIYAmpNW5eZYvU/00f14I634rGNHvOw==
|
||||
X-Received: by 2002:aa7:957c:: with SMTP id
|
||||
x28mr40685571pfq.157.1582339412254;
|
||||
Fri, 21 Feb 2020 18:43:32 -0800 (PST)
|
||||
Received: from localhost.localdomain ([103.219.195.110])
|
||||
by smtp.gmail.com with ESMTPSA id u13sm3797317pjn.29.2020.02.21.18.43.29
|
||||
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
|
||||
Fri, 21 Feb 2020 18:43:31 -0800 (PST)
|
||||
From: Qiang Yu <yuq825@gmail.com>
|
||||
To: dri-devel@lists.freedesktop.org
|
||||
Subject: [PATCH 5/5] drm/lima: add LIMA_BO_FLAG_FORCE_VA
|
||||
Date: Sat, 22 Feb 2020 10:42:10 +0800
|
||||
Message-Id: <20200222024210.18697-6-yuq825@gmail.com>
|
||||
X-Mailer: git-send-email 2.17.1
|
||||
In-Reply-To: <20200222024210.18697-1-yuq825@gmail.com>
|
||||
References: <20200222024210.18697-1-yuq825@gmail.com>
|
||||
X-BeenThere: dri-devel@lists.freedesktop.org
|
||||
X-Mailman-Version: 2.1.29
|
||||
Precedence: list
|
||||
List-Id: Direct Rendering Infrastructure - Development
|
||||
<dri-devel.lists.freedesktop.org>
|
||||
List-Unsubscribe: <https://lists.freedesktop.org/mailman/options/dri-devel>,
|
||||
<mailto:dri-devel-request@lists.freedesktop.org?subject=unsubscribe>
|
||||
List-Archive: <https://lists.freedesktop.org/archives/dri-devel>
|
||||
List-Post: <mailto:dri-devel@lists.freedesktop.org>
|
||||
List-Help: <mailto:dri-devel-request@lists.freedesktop.org?subject=help>
|
||||
List-Subscribe: <https://lists.freedesktop.org/mailman/listinfo/dri-devel>,
|
||||
<mailto:dri-devel-request@lists.freedesktop.org?subject=subscribe>
|
||||
Cc: lima@lists.freedesktop.org, David Airlie <airlied@linux.ie>,
|
||||
Vasily Khoruzhick <anarsoul@gmail.com>,
|
||||
Andreas Baierl <ichgeh@imkreisrum.de>,
|
||||
Qiang Yu <yuq825@gmail.com>, Icenowy Zheng <icenowy@aosc.io>,
|
||||
Erico Nunes <nunes.erico@gmail.com>
|
||||
MIME-Version: 1.0
|
||||
Errors-To: dri-devel-bounces@lists.freedesktop.org
|
||||
Sender: "dri-devel" <dri-devel-bounces@lists.freedesktop.org>
|
||||
|
||||
User can force created buffer to be mapped to GPU VM at a user
|
||||
specified address. This is used for debug tools in user space to
|
||||
replay some task.
|
||||
|
||||
Signed-off-by: Qiang Yu <yuq825@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/lima/lima_drv.c | 26 +++++++++++++++++++-------
|
||||
drivers/gpu/drm/lima/lima_gem.c | 7 +++++--
|
||||
drivers/gpu/drm/lima/lima_gem.h | 4 +++-
|
||||
drivers/gpu/drm/lima/lima_vm.c | 13 ++++++++++++-
|
||||
include/uapi/drm/lima_drm.h | 9 +++++++--
|
||||
5 files changed, 46 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c
|
||||
index 8c5adc025902..f65021ea9598 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_drv.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_drv.c
|
||||
@@ -73,16 +73,27 @@ static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_
|
||||
{
|
||||
struct drm_lima_gem_create *args = data;
|
||||
|
||||
- if (args->pad)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- if (args->flags & ~(LIMA_BO_FLAG_HEAP))
|
||||
+ if (args->flags & ~(LIMA_BO_FLAG_HEAP | LIMA_BO_FLAG_FORCE_VA))
|
||||
return -EINVAL;
|
||||
|
||||
if (args->size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
- return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle);
|
||||
+ if (args->flags & LIMA_BO_FLAG_FORCE_VA) {
|
||||
+ u64 max = (u64)args->va + (u64)args->size;
|
||||
+
|
||||
+ if (max > LIMA_VA_RESERVE_START)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!IS_ALIGNED(args->va, PAGE_SIZE))
|
||||
+ return -EINVAL;
|
||||
+ } else {
|
||||
+ if (args->va)
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return lima_gem_create_handle(dev, file, args->size, args->flags,
|
||||
+ &args->handle, args->va);
|
||||
}
|
||||
|
||||
static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
@@ -253,6 +264,7 @@ DEFINE_DRM_GEM_FOPS(lima_drm_driver_fops);
|
||||
* Changelog:
|
||||
*
|
||||
* - 1.1.0 - add heap buffer support
|
||||
+ * - 1.2.0 - add force va support
|
||||
*/
|
||||
|
||||
static struct drm_driver lima_drm_driver = {
|
||||
@@ -264,9 +276,9 @@ static struct drm_driver lima_drm_driver = {
|
||||
.fops = &lima_drm_driver_fops,
|
||||
.name = "lima",
|
||||
.desc = "lima DRM",
|
||||
- .date = "20191231",
|
||||
+ .date = "20200215",
|
||||
.major = 1,
|
||||
- .minor = 1,
|
||||
+ .minor = 2,
|
||||
.patchlevel = 0,
|
||||
|
||||
.gem_create_object = lima_gem_create_object,
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c
|
||||
index 5404e0d668db..c28d90756584 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gem.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_gem.c
|
||||
@@ -95,7 +95,7 @@ int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm)
|
||||
}
|
||||
|
||||
int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
- u32 size, u32 flags, u32 *handle)
|
||||
+ u32 size, u32 flags, u32 *handle, u32 va)
|
||||
{
|
||||
int err;
|
||||
gfp_t mask;
|
||||
@@ -116,8 +116,11 @@ int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
mask |= __GFP_DMA32;
|
||||
mapping_set_gfp_mask(obj->filp->f_mapping, mask);
|
||||
|
||||
+ bo = to_lima_bo(obj);
|
||||
+ bo->flags = flags;
|
||||
+ bo->force_va = va;
|
||||
+
|
||||
if (is_heap) {
|
||||
- bo = to_lima_bo(obj);
|
||||
err = lima_heap_alloc(bo, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h
|
||||
index ccea06142f4b..2a6db0c0be89 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_gem.h
|
||||
+++ b/drivers/gpu/drm/lima/lima_gem.h
|
||||
@@ -15,6 +15,8 @@ struct lima_bo {
|
||||
struct mutex lock;
|
||||
struct list_head va;
|
||||
|
||||
+ u32 flags;
|
||||
+ u32 force_va;
|
||||
size_t heap_size;
|
||||
};
|
||||
|
||||
@@ -37,7 +39,7 @@ static inline struct dma_resv *lima_bo_resv(struct lima_bo *bo)
|
||||
int lima_heap_alloc(struct lima_bo *bo, struct lima_vm *vm);
|
||||
struct drm_gem_object *lima_gem_create_object(struct drm_device *dev, size_t size);
|
||||
int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file,
|
||||
- u32 size, u32 flags, u32 *handle);
|
||||
+ u32 size, u32 flags, u32 *handle, u32 va);
|
||||
int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset);
|
||||
int lima_gem_submit(struct drm_file *file, struct lima_submit *submit);
|
||||
int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns);
|
||||
diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c
|
||||
index 5b92fb82674a..be0510032538 100644
|
||||
--- a/drivers/gpu/drm/lima/lima_vm.c
|
||||
+++ b/drivers/gpu/drm/lima/lima_vm.c
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
+#include <drm/lima_drm.h>
|
||||
|
||||
#include "lima_device.h"
|
||||
#include "lima_vm.h"
|
||||
@@ -93,6 +94,7 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
|
||||
struct lima_bo_va *bo_va;
|
||||
struct sg_dma_page_iter sg_iter;
|
||||
int offset = 0, err;
|
||||
+ u64 start, end;
|
||||
|
||||
mutex_lock(&bo->lock);
|
||||
|
||||
@@ -120,7 +122,16 @@ int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create)
|
||||
|
||||
mutex_lock(&vm->lock);
|
||||
|
||||
- err = drm_mm_insert_node(&vm->mm, &bo_va->node, lima_bo_size(bo));
|
||||
+ if (bo->flags & LIMA_BO_FLAG_FORCE_VA) {
|
||||
+ start = bo->force_va;
|
||||
+ end = start + lima_bo_size(bo);
|
||||
+ } else {
|
||||
+ start = 0;
|
||||
+ end = U64_MAX;
|
||||
+ }
|
||||
+
|
||||
+ err = drm_mm_insert_node_in_range(&vm->mm, &bo_va->node, lima_bo_size(bo),
|
||||
+ 0, 0, start, end, 0);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
|
||||
diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h
|
||||
index 1ec58d652a5a..3e699bb78394 100644
|
||||
--- a/include/uapi/drm/lima_drm.h
|
||||
+++ b/include/uapi/drm/lima_drm.h
|
||||
@@ -37,7 +37,12 @@ struct drm_lima_get_param {
|
||||
* due to lack of heap memory. size field of heap buffer is an up bound of
|
||||
* the backup memory which can be set to a fairly large value.
|
||||
*/
|
||||
-#define LIMA_BO_FLAG_HEAP (1 << 0)
|
||||
+#define LIMA_BO_FLAG_HEAP (1 << 0)
|
||||
+/*
|
||||
+ * force buffer GPU virtual address to be drm_lima_gem_create.va, this is
|
||||
+ * used to replay some task with fixed GPU virtual address
|
||||
+ */
|
||||
+#define LIMA_BO_FLAG_FORCE_VA (1 << 1)
|
||||
|
||||
/**
|
||||
* create a buffer for used by GPU
|
||||
@@ -46,7 +51,7 @@ struct drm_lima_gem_create {
|
||||
__u32 size; /* in, buffer size */
|
||||
__u32 flags; /* in, buffer flags */
|
||||
__u32 handle; /* out, GEM buffer handle */
|
||||
- __u32 pad; /* pad, must be zero */
|
||||
+ __u32 va; /* in, buffer va */
|
||||
};
|
||||
|
||||
/**
|
@ -1,18 +0,0 @@
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
index 086b5ebfa512..b4a71b02c474 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
@@ -304,11 +304,13 @@ &codec {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&aif2_pins>, <&aif3_pins>;
|
||||
status = "okay";
|
||||
+ allwinner,inverted-jack-detection;
|
||||
};
|
||||
|
||||
&codec_analog {
|
||||
cpvdd-supply = <®_eldo1>;
|
||||
status = "okay";
|
||||
+ allwinner,internal-bias-resistor;
|
||||
};
|
||||
|
||||
&cpu0 {
|
@ -1,175 +0,0 @@
|
||||
From 5da6a7e3f4d6e11f4887893672f849d2d4fa5b58 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Wed, 16 Dec 2020 20:16:14 -0800
|
||||
Subject: [PATCH] dts: pinephone: drop modem-power node
|
||||
|
||||
---
|
||||
.../allwinner/sun50i-a64-pinephone-1.0.dts | 26 +++---------------
|
||||
.../allwinner/sun50i-a64-pinephone-1.1.dts | 27 +++----------------
|
||||
.../allwinner/sun50i-a64-pinephone-1.2.dts | 27 +++----------------
|
||||
.../dts/allwinner/sun50i-a64-pinephone.dtsi | 12 +++++++++
|
||||
4 files changed, 24 insertions(+), 68 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
index 0f6faa44ce3e..2cc513772172 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.0.dts
|
||||
@@ -86,28 +86,6 @@ ®_drivevbus {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
-&uart3 {
|
||||
- modem {
|
||||
- compatible = "quectel,eg25";
|
||||
- char-device-name = "modem-power";
|
||||
-
|
||||
- power-supply = <®_vbat_bb>; /* PL7 */
|
||||
-
|
||||
- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */
|
||||
- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */
|
||||
- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
|
||||
-
|
||||
- sleep-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
|
||||
- wakeup-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-RI */
|
||||
-
|
||||
- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */
|
||||
- dtr-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-DTR */
|
||||
- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */
|
||||
-
|
||||
- quectel,qdai = "1,1,0,1,0,0,1,1";
|
||||
- };
|
||||
-};
|
||||
-
|
||||
&usbphy {
|
||||
usb-role-switch;
|
||||
|
||||
@@ -118,6 +96,10 @@ usb0_drd_sw: endpoint {
|
||||
};
|
||||
};
|
||||
|
||||
+&ring_indicator {
|
||||
+ gpios = <&pio 1 2 GPIO_ACTIVE_LOW>; /* PB2 */
|
||||
+};
|
||||
+
|
||||
&sgm3140 {
|
||||
flash-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
|
||||
enable-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
index 95a880fdc9ce..5f3b6a1a142f 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
@@ -109,34 +109,15 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&ring_indicator {
|
||||
+ gpios = <&pio 1 2 GPIO_ACTIVE_LOW>; /* PB2 */
|
||||
+};
|
||||
+
|
||||
&sgm3140 {
|
||||
enable-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
|
||||
flash-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */
|
||||
};
|
||||
|
||||
-&uart3 {
|
||||
- modem {
|
||||
- compatible = "quectel,eg25";
|
||||
- char-device-name = "modem-power";
|
||||
-
|
||||
- power-supply = <®_vbat_bb>; /* PL7 */
|
||||
-
|
||||
- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */
|
||||
- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */
|
||||
- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
|
||||
- //status-pwrkey-multiplexed; /* status acts as pwrkey */
|
||||
-
|
||||
- sleep-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
|
||||
- wakeup-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-RI */
|
||||
-
|
||||
- dtr-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-DTR */
|
||||
- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */
|
||||
- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */
|
||||
-
|
||||
- quectel,qdai = "1,1,0,1,0,0,1,1";
|
||||
- };
|
||||
-};
|
||||
-
|
||||
&usbphy {
|
||||
usb-role-switch;
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
index 23ba72508cfc..889841ca5b8a 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
@@ -101,34 +101,15 @@
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
+&ring_indicator {
|
||||
+ gpios = <&r_pio 0 6 GPIO_ACTIVE_LOW>; /* PL6 */
|
||||
+};
|
||||
+
|
||||
&sgm3140 {
|
||||
enable-gpios = <&pio 3 24 GPIO_ACTIVE_HIGH>; /* PD24 */
|
||||
flash-gpios = <&pio 2 3 GPIO_ACTIVE_HIGH>; /* PC3 */
|
||||
};
|
||||
|
||||
-&uart3 {
|
||||
- modem {
|
||||
- compatible = "quectel,eg25";
|
||||
- char-device-name = "modem-power";
|
||||
-
|
||||
- power-supply = <®_vbat_bb>; /* PL7 */
|
||||
-
|
||||
- enable-gpios = <&pio 7 8 GPIO_ACTIVE_LOW>; /* PH8 */
|
||||
- reset-gpios = <&pio 2 4 GPIO_ACTIVE_HIGH>; /* PC4 */
|
||||
- status-gpios = <&pio 7 9 GPIO_ACTIVE_HIGH>; /* PH9 */
|
||||
- pwrkey-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
|
||||
-
|
||||
- host-ready-gpios = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
|
||||
- wakeup-gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; /* PL6-RI */
|
||||
-
|
||||
- dtr-gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2-DTR */
|
||||
- cts-gpios = <&pio 3 5 GPIO_ACTIVE_HIGH>; /* PD5-CTS */
|
||||
- rts-gpios = <&pio 3 4 GPIO_ACTIVE_HIGH>; /* PD4-RTS */
|
||||
-
|
||||
- quectel,qdai = "1,1,0,1,0,0,1,1";
|
||||
- };
|
||||
-};
|
||||
-
|
||||
&usbphy {
|
||||
usb-role-switch;
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
index 02d82980cf39..979d01de8d84 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
@@ -192,6 +192,17 @@ ec25_codec: ec25-codec {
|
||||
compatible = "quectel,ec25";
|
||||
};
|
||||
|
||||
+ gpio-keys {
|
||||
+ compatible = "gpio-keys";
|
||||
+
|
||||
+ ring_indicator: ring-indicator {
|
||||
+ label = "Ring Indicator";
|
||||
+ linux,can-disable;
|
||||
+ linux,code = <KEY_WAKEUP>;
|
||||
+ wakeup-source;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
i2c_csi: i2c-csi {
|
||||
compatible = "i2c-gpio";
|
||||
sda-gpios = <&pio 4 13 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; /* PE13 */
|
||||
@@ -256,6 +267,7 @@ reg_usb_5v: usb-5v {
|
||||
reg_vbat_bb: vbat-bb {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-bb";
|
||||
+ regulator-always-on;
|
||||
regulator-min-microvolt = <3500000>;
|
||||
regulator-max-microvolt = <3500000>;
|
||||
gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
|
||||
--
|
||||
2.29.2
|
||||
|
@ -1,67 +0,0 @@
|
||||
From de578360d41d166ca75b0624e72c5b14f56c0bdf Mon Sep 17 00:00:00 2001
|
||||
From: Arnaud Ferraris <arnaud.ferraris@collabora.com>
|
||||
Date: Wed, 19 Aug 2020 13:10:02 +0200
|
||||
Subject: [PATCH] arm64: dts: sun50i-a64-pinephone: improve brightness values
|
||||
on BH/CE
|
||||
|
||||
Commit aad90c10 caused a brightness increase with the previous values.
|
||||
Subsequently, the lowest brightness value would still be fairly bright.
|
||||
|
||||
This commit aims at providing a wider range of usable brightness for
|
||||
1.1+ devices.
|
||||
|
||||
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@collabora.com>
|
||||
---
|
||||
.../boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts | 10 +++++-----
|
||||
.../boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts | 13 ++++++-------
|
||||
2 files changed, 11 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
index 2f993ffc6..c8dcd2291 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
@@ -34,11 +34,11 @@ &backlight {
|
||||
* value here was chosen as a safe default.
|
||||
*/
|
||||
brightness-levels = <
|
||||
- 774 793 814 842
|
||||
- 882 935 1003 1088
|
||||
- 1192 1316 1462 1633
|
||||
- 1830 2054 2309 2596
|
||||
- 2916 3271 3664 4096>;
|
||||
+ 392 413 436 468
|
||||
+ 512 571 647 742
|
||||
+ 857 995 1159 1349
|
||||
+ 1568 1819 2103 2423
|
||||
+ 2779 3176 3614 4096>;
|
||||
num-interpolated-steps = <50>;
|
||||
default-brightness-level = <400>;
|
||||
};
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
index 6c3019933..017104df2 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
@@ -24,14 +24,13 @@ &backlight {
|
||||
* chosen as a safe default.
|
||||
*/
|
||||
brightness-levels = <
|
||||
- 5000 5248 5506 5858 6345
|
||||
- 6987 7805 8823 10062 11543
|
||||
- 13287 15317 17654 20319 23336
|
||||
- 26724 30505 34702 39335 44427
|
||||
- 50000
|
||||
- >;
|
||||
+ 392 413 436 468
|
||||
+ 512 571 647 742
|
||||
+ 857 995 1159 1349
|
||||
+ 1568 1819 2103 2423
|
||||
+ 2779 3176 3614 4096>;
|
||||
num-interpolated-steps = <50>;
|
||||
- default-brightness-level = <500>;
|
||||
+ default-brightness-level = <400>;
|
||||
};
|
||||
|
||||
&lis3mdl {
|
||||
--
|
||||
2.28.0
|
||||
|
@ -1,67 +0,0 @@
|
||||
From de578360d41d166ca75b0624e72c5b14f56c0bdf Mon Sep 17 00:00:00 2001
|
||||
From: Arnaud Ferraris <arnaud.ferraris@collabora.com>
|
||||
Date: Wed, 19 Aug 2020 13:10:02 +0200
|
||||
Subject: [PATCH] arm64: dts: sun50i-a64-pinephone: improve brightness values
|
||||
on BH/CE
|
||||
|
||||
Commit aad90c10 caused a brightness increase with the previous values.
|
||||
Subsequently, the lowest brightness value would still be fairly bright.
|
||||
|
||||
This commit aims at providing a wider range of usable brightness for
|
||||
1.1+ devices.
|
||||
|
||||
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@collabora.com>
|
||||
---
|
||||
.../boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts | 10 +++++-----
|
||||
.../boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts | 13 ++++++-------
|
||||
2 files changed, 11 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
index 2f993ffc6..c8dcd2291 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.1.dts
|
||||
@@ -34,11 +34,11 @@ &backlight {
|
||||
* value here was chosen as a safe default.
|
||||
*/
|
||||
brightness-levels = <
|
||||
- 774 793 814 842
|
||||
- 882 935 1003 1088
|
||||
- 1192 1316 1462 1633
|
||||
- 1830 2054 2309 2596
|
||||
- 2916 3271 3664 4096>;
|
||||
+ 392 413 436 468
|
||||
+ 512 571 647 742
|
||||
+ 857 995 1159 1349
|
||||
+ 1568 1819 2103 2423
|
||||
+ 2779 3176 3614 4096>;
|
||||
num-interpolated-steps = <50>;
|
||||
default-brightness-level = <400>;
|
||||
};
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
index 6c3019933..017104df2 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone-1.2.dts
|
||||
@@ -24,14 +24,13 @@ &backlight {
|
||||
* chosen as a safe default.
|
||||
*/
|
||||
brightness-levels = <
|
||||
- 5000 5248 5506 5858 6345
|
||||
- 6987 7805 8823 10062 11543
|
||||
- 13287 15317 17654 20319 23336
|
||||
- 26724 30505 34702 39335 44427
|
||||
- 50000
|
||||
- >;
|
||||
+ 392 413 436 468
|
||||
+ 512 571 647 742
|
||||
+ 857 995 1159 1349
|
||||
+ 1568 1819 2103 2423
|
||||
+ 2779 3176 3614 4096>;
|
||||
num-interpolated-steps = <50>;
|
||||
- default-brightness-level = <500>;
|
||||
+ default-brightness-level = <400>;
|
||||
};
|
||||
|
||||
&lis3mdl {
|
||||
--
|
||||
2.28.0
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- linux-pine64-5.9-da1a1dee4471aa5da391517c4af40d2c80fe828d/drivers/media/i2c/ov5640.c 2020-10-18 00:13:18.000000000 +0200
|
||||
+++ linux-pine64-5.9-da1a1dee4471aa5da391517c4af40d2c80fe828d/drivers/media/i2c/ov5640.c 2020-10-18 22:19:32.490533074 +0200
|
||||
@@ -2677,7 +2677,7 @@ static int ov5640_set_ctrl_focus(struct
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s: no autofocus firmware loaded\n",
|
||||
__func__);
|
||||
- return ret;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
if (command == OV5640_FW_CMD_RELEASE_FOCUS) {
|
@ -1,36 +0,0 @@
|
||||
From 29533cb13f24e26e7ddbc044597a3020437352e2 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman
|
||||
Date: Thu, 29 Oct 2020 01:13:49 +0100
|
||||
Subject: drm/sun4i: Fix mipi-dsi panel framerate being 2/3 of the expected
|
||||
value
|
||||
|
||||
This happens on Pinephone and on Pinetab. Both use MIPI-DSI panels.
|
||||
|
||||
On Pinephone framerate is 36.6 instead of expected 55.
|
||||
On Pinetab the similar 2/3 ratio holds.
|
||||
|
||||
Myabe there's a bug in BSP and dclk_div should really be 6 instead of 4.
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun4i_tcon.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
||||
index ab06f5e1fc95..1c56b4fb9ac8 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
|
||||
@@ -398,8 +398,8 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
|
||||
u32 block_space, start_delay;
|
||||
u32 tcon_div;
|
||||
|
||||
- tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
|
||||
- tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
|
||||
+ tcon->dclk_min_div = 6;
|
||||
+ tcon->dclk_max_div = 6;
|
||||
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
|
||||
--
|
||||
cgit v1.2.3
|
||||
|
@ -1,37 +0,0 @@
|
||||
From e8be2e4affb906af7137437ac62fb3912609c11e Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman
|
||||
Date: Thu, 29 Oct 2020 04:55:40 +0100
|
||||
Subject: drm: panel: st7703: Fix xbd599 timings to make refresh rate exactly
|
||||
60.006Hz
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
drivers/gpu/drm/panel/panel-sitronix-st7703.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
|
||||
index 4287aabb9007..070ef2baef6f 100644
|
||||
--- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c
|
||||
@@ -334,14 +334,14 @@ static int xbd599_init_sequence(struct st7703 *ctx)
|
||||
|
||||
static const struct drm_display_mode xbd599_mode = {
|
||||
.hdisplay = 720,
|
||||
- .hsync_start = 720 + 40,
|
||||
- .hsync_end = 720 + 40 + 40,
|
||||
- .htotal = 720 + 40 + 40 + 40,
|
||||
+ .hsync_start = 720 + 30,
|
||||
+ .hsync_end = 720 + 30 + 28,
|
||||
+ .htotal = 720 + 30 + 28 + 30,
|
||||
.vdisplay = 1440,
|
||||
.vsync_start = 1440 + 18,
|
||||
.vsync_end = 1440 + 18 + 10,
|
||||
.vtotal = 1440 + 18 + 10 + 17,
|
||||
- .clock = 69000,
|
||||
+ .clock = 72000,
|
||||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||
.width_mm = 68,
|
||||
.height_mm = 136,
|
||||
--
|
||||
cgit v1.2.3
|
||||
|
@ -1,66 +0,0 @@
|
||||
From 8a0bf7456f10a06adeeed0690d181f67d887e18e Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman
|
||||
Date: Tue, 28 Jan 2020 00:26:17 +0100
|
||||
Subject: drm: sun4i-drm: Recover from occasional HW failures
|
||||
|
||||
Layer can be disabled automatically by HW (HW clears the bit in
|
||||
some unknown situations). We need to always update this bit,
|
||||
so that DE2 will not fail.
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 13 ++++++-------
|
||||
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 13 ++++++-------
|
||||
2 files changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
index f1c87695b4d7..e58482f6d7ba 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
|
||||
@@ -36,13 +36,12 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
|
||||
DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
|
||||
enable ? "En" : "Dis", channel, overlay);
|
||||
|
||||
- if (!was_enabled != !enable) {
|
||||
- val = enable ? SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN : 0;
|
||||
-
|
||||
- regmap_update_bits(mixer->engine.regs,
|
||||
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
|
||||
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
|
||||
- }
|
||||
+ /* We always update the layer enable bit, because it can clear
|
||||
+ * spontaneously for unknown reasons. */
|
||||
+ val = enable ? SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN : 0;
|
||||
+ regmap_update_bits(mixer->engine.regs,
|
||||
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
|
||||
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
|
||||
|
||||
/*
|
||||
* If this layer was enabled and is being disabled or if it is
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
index 81eda71c4fff..0c2ccc33d456 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
|
||||
@@ -30,13 +30,12 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
|
||||
DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
|
||||
enable ? "En" : "Dis", channel, overlay);
|
||||
|
||||
- if (!was_enabled != !enable) {
|
||||
- val = enable ? SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN : 0;
|
||||
-
|
||||
- regmap_update_bits(mixer->engine.regs,
|
||||
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
|
||||
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
|
||||
- }
|
||||
+ /* We always update the layer enable bit, because it can clear
|
||||
+ * spontaneously for unknown reasons. */
|
||||
+ val = enable ? SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN : 0;
|
||||
+ regmap_update_bits(mixer->engine.regs,
|
||||
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
|
||||
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
|
||||
|
||||
/*
|
||||
* If this layer was enabled and is being disabled or if it is
|
||||
--
|
||||
cgit v1.2.3
|
||||
|
@ -1,44 +0,0 @@
|
||||
From 2af59597979e0192cb4675c12e57ed2a857fe9ce Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Jirman
|
||||
Date: Wed, 7 Oct 2020 02:11:35 +0200
|
||||
Subject: clk: sunxi-ng: sun50i-a64: Switch parent of MIPI-DSI to periph0(1x)
|
||||
|
||||
This makes video0(1x) clock less constrained, and improves compatibility
|
||||
with external monitors on Pinephone when using both internal display
|
||||
and HDMI output at once.
|
||||
|
||||
Signed-off-by: Ondrej Jirman <megous@megous.com>
|
||||
Modified by: Philip Müller <philm@manjaro.org>
|
||||
---
|
||||
drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
|
||||
index 8ac40a78e75e..e41eadc602e7 100644
|
||||
--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
|
||||
+++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
|
||||
@@ -969,6 +969,8 @@ static struct ccu_rate_reset_nb sun50i_a
|
||||
.common = &pll_video0_clk.common,
|
||||
};
|
||||
|
||||
+#define CCU_MIPI_DSI_CLK 0x168
|
||||
+
|
||||
static int sun50i_a64_ccu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
@@ -990,6 +992,12 @@ static int sun50i_a64_ccu_probe(struct p
|
||||
writel(0x10040000, reg + SUN50I_A64_PLL_AUDIO_BIAS_REG);
|
||||
|
||||
writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG);
|
||||
+
|
||||
+ /* Set MIPI-DSI clock parent to periph0(1x), so that video0(1x) is free to change. */
|
||||
+ val = readl(reg + CCU_MIPI_DSI_CLK);
|
||||
+ val &= 0x30f;
|
||||
+ val |= (2 << 8) | ((4 - 1) << 0); /* M-1 */
|
||||
+ writel(val, reg + CCU_MIPI_DSI_CLK);
|
||||
|
||||
/* Force the parent of TCON0 to PLL-MIPI */
|
||||
val = readl(reg + SUN50I_A64_TCON0_REG);
|
||||
--
|
||||
cgit v1.2.3
|
||||
|
@ -1,26 +0,0 @@
|
||||
From 5a3d7fd96843710d468603412a3270e7eefe997a Mon Sep 17 00:00:00 2001
|
||||
From: Danct12 <danct12@disroot.org>
|
||||
Date: Wed, 14 Oct 2020 01:18:40 +0700
|
||||
Subject: [PATCH] arm64: dts: pinephone: remove flash node for ov5640
|
||||
|
||||
Signed-off-by: Danct12 <danct12@disroot.org>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
index 3781eb8ea..6bc0e9d6d 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
|
||||
@@ -439,8 +439,6 @@ ov5640: rear-camera@4c {
|
||||
reset-gpios = <&pio 3 3 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; /* PD3 */
|
||||
powerdown-gpios = <&pio 2 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; /* PC0 */
|
||||
|
||||
- flash-leds = <&sgm3140_flash>;
|
||||
-
|
||||
port {
|
||||
ov5640_ep: endpoint {
|
||||
remote-endpoint = <&csi_ov5640_ep>;
|
||||
--
|
||||
2.28.0
|
||||
|
@ -1,35 +0,0 @@
|
||||
From 3ed430f6b94479c7b4d26323b5fe6381ca11c0e4 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Lindgren <tony@atomide.com>
|
||||
Date: Tue, 27 Oct 2020 13:18:57 +0530
|
||||
Subject: [PATCH] usb: musb: avoid the hang in musb_pm_runtime_check_session
|
||||
|
||||
See thread at: https://lore.kernel.org/linux-usb/20201027045519.GA947883@aquila.localdomain/
|
||||
---
|
||||
drivers/usb/musb/musb_core.c | 11 +++++++----
|
||||
1 file changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
|
||||
index 384a8039a7fd5..fe87046d8b28a 100644
|
||||
--- a/drivers/usb/musb/musb_core.c
|
||||
+++ b/drivers/usb/musb/musb_core.c
|
||||
@@ -2005,10 +2005,13 @@ static void musb_pm_runtime_check_session(struct musb *musb)
|
||||
MUSB_DEVCTL_HR;
|
||||
switch (devctl & ~s) {
|
||||
case MUSB_QUIRK_B_DISCONNECT_99:
|
||||
- musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
|
||||
- schedule_delayed_work(&musb->irq_work,
|
||||
- msecs_to_jiffies(1000));
|
||||
- break;
|
||||
+ if (musb->quirk_retries && !musb->flush_irq_work) {
|
||||
+ musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
|
||||
+ schedule_delayed_work(&musb->irq_work,
|
||||
+ msecs_to_jiffies(1000));
|
||||
+ musb->quirk_retries--;
|
||||
+ break;
|
||||
+ }
|
||||
case MUSB_QUIRK_B_INVALID_VBUS_91:
|
||||
if (musb->quirk_retries && !musb->flush_irq_work) {
|
||||
musb_dbg(musb,
|
||||
--
|
||||
2.29.1
|
||||
|
@ -1,34 +0,0 @@
|
||||
From 62b516401f008d166b93ad2ea6f3012989b0cccb Mon Sep 17 00:00:00 2001
|
||||
From: Dalton <dalton@ubports.com>
|
||||
Date: Tue, 23 Jun 2020 20:54:12 -0500
|
||||
Subject: [PATCH] UBPORTS SAUCE: Disable 8723cs power saving
|
||||
|
||||
The runtime power management features in the 8723cs firmware on the
|
||||
PinePhone don't seem to work correctly. While we expect the chipset to
|
||||
leave a low power state when it's time to send or receive data, instead
|
||||
we get a delay of 10-20 seconds before any packets are sent.
|
||||
---
|
||||
drivers/staging/rtl8723cs-new/os_dep/linux/os_intfs.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/staging/rtl8723cs-new/os_dep/linux/os_intfs.c b/drivers/staging/rtl8723cs-new/os_dep/linux/os_intfs.c
|
||||
index 3e6ba0a0fd17..5bb850a4caf0 100644
|
||||
--- a/drivers/staging/rtl8723cs-new/os_dep/linux/os_intfs.c
|
||||
+++ b/drivers/staging/rtl8723cs-new/os_dep/linux/os_intfs.c
|
||||
@@ -54,7 +54,12 @@ int rtw_adhoc_tx_pwr = 1;
|
||||
int rtw_soft_ap = 0;
|
||||
/* int smart_ps = 1; */
|
||||
#ifdef CONFIG_POWER_SAVING
|
||||
- int rtw_power_mgnt = PS_MODE_MAX;
|
||||
+ // Setting PS_MODE_ACTIVE by default keeps the power saving code in the
|
||||
+ // driver but works around an issue where the 8723cs won't leave Leisure
|
||||
+ // Power Saving mode without long delays. Allows for testing different
|
||||
+ // firmwares.
|
||||
+ // int rtw_power_mgnt = PS_MODE_MAX;
|
||||
+ int rtw_power_mgnt = PS_MODE_ACTIVE;
|
||||
#ifdef CONFIG_IPS_LEVEL_2
|
||||
int rtw_ips_mode = IPS_LEVEL_2;
|
||||
#else
|
||||
--
|
||||
GitLab
|
||||
|
@ -17,7 +17,7 @@ MEGI_PATCH_URI="https://xff.cz/kernels/${PV:0:4}/patches/all.patch"
|
||||
SRC_URI="${KERNEL_URI} ${MEGI_PATCH_URI} -> all-${PV}.patch"
|
||||
|
||||
PATCHES=(
|
||||
${DISTDIR}/all-${PV}.patch
|
||||
${DISTDIR}/all-${PV}.patch
|
||||
${FILESDIR}/enable-hdmi-output-pinetab.patch
|
||||
${FILESDIR}/enable-jack-detection-pinetab.patch
|
||||
${FILESDIR}/pinetab-bluetooth.patch
|
||||
@ -37,7 +37,6 @@ PATCHES=(
|
||||
${FILESDIR}/PATCH-1-4-HID-magicmouse-add-Apple-Magic-Mouse-2-support.patch
|
||||
${FILESDIR}/PATCH-2-4-HID-magicmouse-fix-3-button-emulation-of-Mouse-2.patch
|
||||
${FILESDIR}/PATCH-3-4-HID-magicmouse-fix-reconnection-of-Magic-Mouse-2.patch
|
||||
${FILESDIR}/PATCH-4-4-HID-input-map-battery-capacity-00850065.patch
|
||||
)
|
||||
|
||||
src_prepare() {
|
||||
|
Loading…
Reference in New Issue
Block a user