firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-fs_pstore_blkoops.c.p...

236 lines
6.4 KiB
Diff

diff -drupN a/fs/pstore/blkoops.c b/fs/pstore/blkoops.c
--- a/fs/pstore/blkoops.c 1970-01-01 03:00:00.000000000 +0300
+++ b/fs/pstore/blkoops.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * blkoops.c: Block device Oops logger
+ *
+ * Copyright (C) 2019 liaoweixiong <liaoweixiong@gallwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#define MODNAME "blkoops"
+#define pr_fmt(fmt) MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pstore_blk.h>
+
+static long dmesg_size = -1;
+module_param(dmesg_size, long, 0400);
+MODULE_PARM_DESC(dmesg_size, "demsg size in kbytes");
+
+static long pmsg_size = -1;
+module_param(pmsg_size, long, 0400);
+MODULE_PARM_DESC(pmsg_size, "pmsg size in kbytes");
+
+static long total_size = -1;
+module_param(total_size, long, 0400);
+MODULE_PARM_DESC(total_size, "total size in kbytes");
+
+static int dump_oom = -1;
+module_param(dump_oom, int, 0400);
+MODULE_PARM_DESC(total_size, "whether dump oom");
+
+static int dump_oops = -1;
+module_param(dump_oops, int, 0400);
+MODULE_PARM_DESC(total_size, "whether dump oops");
+
+#define BLKDEV_INVALID "INVALID"
+static char blkdev[80] = {BLKDEV_INVALID};
+module_param_string(blkdev, blkdev, 80, 0400);
+MODULE_PARM_DESC(blkdev, "the block device for general read/write");
+
+struct blkz_info blkz_info = {
+ .owner = THIS_MODULE,
+ .name = "blkoops",
+};
+
+struct blkoops_info {
+ unsigned long dmesg_size;
+ unsigned long pmsg_size;
+ unsigned long total_size;
+ int dump_oops;
+ int dump_oom;
+ const char *blkdev;
+};
+struct blkoops_info blkoops_info = {
+ .dmesg_size = CONFIG_PSTORE_BLKOOPS_DMESG_SIZE * 1024,
+ .pmsg_size = CONFIG_PSTORE_BLKOOPS_PMSG_SIZE * 1024,
+ .total_size = CONFIG_PSTORE_BLKOOPS_TOTAL_SIZE * 1024,
+ .blkdev = CONFIG_PSTORE_BLKOOPS_BLKDEV,
+#if IS_ENABLED(CONFIG_PSTORE_BLKOOPS_DUMP_OOPS)
+ .dump_oops = CONFIG_PSTORE_BLKOOPS_DUMP_OOPS,
+#endif
+#if IS_ENABLED(CONFIG_PSTORE_BLKOOPS_DUMP_OOM)
+ .dump_oom = CONFIG_PSTORE_BLKOOPS_DUMP_OOM,
+#endif
+};
+
+static struct platform_device *dummy;
+DEFINE_SPINLOCK(modify_blkzinfo);
+
+/**
+ * Block driver use this function to add panic read/write apis to blkoops.
+ * By this, block driver can do the least work that just provides panic ops.
+ */
+int blkoops_add_panic_ops(blkz_read_op panic_read, blkz_write_op panic_write)
+{
+ struct blkz_info *info = &blkz_info;
+
+ spin_lock(&modify_blkzinfo);
+ if (info->panic_read || info->panic_write) {
+ spin_unlock(&modify_blkzinfo);
+ return -EBUSY;
+ }
+
+ info->panic_read = panic_read;
+ info->panic_write = panic_write;
+
+ spin_unlock(&modify_blkzinfo);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(blkoops_add_panic_ops);
+
+static int blkoops_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct blkoops_info *info = dev->platform_data;
+
+ if (info->blkdev[0] == '\0' || !strcmp(info->blkdev, BLKDEV_INVALID)) {
+ pr_info("no block device, use ram buffer only\n");
+ } else {
+ pr_debug("block device: %s\n", info->blkdev);
+ blkz_info.blkdev = info->blkdev;
+ }
+
+ blkz_info.dump_oom = !!info->dump_oom;
+ blkz_info.dump_oops = !!info->dump_oops;
+#define check_size(name, size) { \
+ if (info->name & (size - 1)) { \
+ pr_err(#name " must be a multiple of %d\n", \
+ (size)); \
+ return -EINVAL; \
+ } \
+ blkz_info.name = info->name; \
+ }
+
+ check_size(total_size, 4096);
+ check_size(dmesg_size, 4096);
+ check_size(pmsg_size, 4096);
+
+#undef check_size
+
+ /*
+ * Update the module parameter variables as well so they are visible
+ * through /sys/module/blkoops/parameters/
+ */
+ dmesg_size = blkz_info.dmesg_size;
+ pmsg_size = blkz_info.pmsg_size;
+ total_size = blkz_info.total_size;
+ dump_oops = blkz_info.dump_oops;
+ dump_oom = blkz_info.dump_oom;
+ if (blkz_info.blkdev)
+ strncpy(blkdev, blkz_info.blkdev, 80 - 1);
+ else
+ blkdev[0] = '\0';
+ return blkz_register(&blkz_info);
+}
+
+static int blkoops_remove(struct platform_device *pdev)
+{
+ blkz_unregister(&blkz_info);
+ return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = MODNAME},
+ {}
+};
+
+static struct platform_driver blkoops_driver = {
+ .probe = blkoops_probe,
+ .remove = blkoops_remove,
+ .driver = {
+ .name = MODNAME,
+ .of_match_table = dt_match,
+ },
+};
+
+void blkoops_register_dummy(void)
+{
+ struct blkoops_info *info = &blkoops_info;
+
+ /*
+ * Prepare a dummy platform data structure to carry the module
+ * parameters or kconfig value.
+ */
+ if (total_size > 0 || strcmp(blkdev, BLKDEV_INVALID)) {
+ pr_info("using module parameters\n");
+ if (total_size >= 0)
+ info->total_size = (unsigned long)total_size * 1024;
+ if (strcmp(blkdev, BLKDEV_INVALID))
+ info->blkdev = (const char *)blkdev;
+ if (dmesg_size >= 0)
+ info->dmesg_size = (unsigned long)dmesg_size * 1024;
+ if (pmsg_size >= 0)
+ info->pmsg_size = (unsigned long)pmsg_size * 1024;
+ if (dump_oops >= 0)
+ info->dump_oops = dump_oops;
+ if (dump_oom >= 0)
+ info->dump_oops = dump_oom;
+ } else if (info->total_size > 0 || strlen(info->blkdev)) {
+ pr_info("using kconfig value\n");
+ } else {
+ return;
+ }
+
+ dummy = platform_device_register_data(NULL, MODNAME, -1, info,
+ sizeof(*info));
+ if (IS_ERR(dummy)) {
+ pr_err("could not create platform device: %ld\n",
+ PTR_ERR(dummy));
+ dummy = NULL;
+ }
+}
+
+static int __init blkoops_init(void)
+{
+ int ret;
+
+ blkoops_register_dummy();
+ ret = platform_driver_register(&blkoops_driver);
+ if (ret != 0) {
+ platform_device_unregister(dummy);
+ dummy = NULL;
+ }
+ return ret;
+}
+late_initcall(blkoops_init);
+
+static void __exit blkoops_exit(void)
+{
+ platform_driver_unregister(&blkoops_driver);
+ platform_device_unregister(dummy);
+ dummy = NULL;
+}
+module_exit(blkoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("liaoweixiong <liaoweixiong@allwinnertech.com>");
+MODULE_DESCRIPTION("Sample for Pstore BLK with Oops logger");