mirror of https://github.com/OpenIPC/firmware.git
236 lines
6.4 KiB
Diff
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");
|