kernel_samsung_a53x/drivers/soc/samsung/debug/debug-snapshot-debug-kinfo.c

133 lines
3.5 KiB
C
Raw Normal View History

2024-06-15 16:02:09 -03:00
// SPDX-License-Identifier: GPL-2.0
/*
* debug-snapshot-debug-kinfo.c - prepare memory for the debug-kinfo driver
*
* Copyright 2020 Google LLC
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*/
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <asm/pgtable.h>
#include <generated/utsrelease.h>
#include <soc/samsung/debug-snapshot.h>
#include "../../../../drivers/staging/android/debug_kinfo.h"
struct vendor_kernel_info {
/* For linux banner */
__u8 uts_release[__NEW_UTS_LEN];
} __packed;
struct vendor_kernel_all_info {
__u32 magic_number;
__u32 combined_checksum;
struct vendor_kernel_info info;
} __packed;
static void update_vendor_kernel_all_info(struct vendor_kernel_all_info *all_info)
{
int index;
struct vendor_kernel_info *info;
u32 *vendor_checksum_info;
all_info->magic_number = DEBUG_KINFO_MAGIC;
all_info->combined_checksum = 0;
info = &all_info->info;
vendor_checksum_info = (u32 *)info;
for (index = 0; index < sizeof(*info) / sizeof(u32); index++)
all_info->combined_checksum ^= vendor_checksum_info[index];
}
static int debug_snapshot_debug_kinfo_probe(struct platform_device *pdev)
{
int i;
struct reserved_mem *rmem;
struct device_node *mem_region;
phys_addr_t base, size, offset;
unsigned int num_pages;
unsigned long flags = VM_NO_GUARD | VM_MAP;
struct page **pages;
void *vaddr;
struct vendor_kernel_all_info *all_info;
struct vendor_kernel_info *info;
mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
if (!mem_region) {
dev_warn(&pdev->dev, "no such memory-region\n");
return 0;
}
rmem = of_reserved_mem_lookup(mem_region);
if (!rmem) {
dev_warn(&pdev->dev, "no such reserved mem of node name %s\n",
&pdev->dev.of_node->name);
return 0;
}
base = rmem->base;
size = rmem->size;
offset = size / 2;
if (!base || !size || (size - offset) < sizeof(struct vendor_kernel_all_info)) {
dev_warn(&pdev->dev,
"unexpected reserved memory(base[%pa], size [%pa])\n",
&base, &size);
return 0;
}
num_pages = (size >> PAGE_SHIFT);
if (size > (num_pages << PAGE_SHIFT))
num_pages++;
pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
for (i = 0; i < num_pages; i++) {
pages[i] = phys_to_page(base);
base += PAGE_SIZE;
}
vaddr = vmap(pages, num_pages, flags, pgprot_writecombine(PAGE_KERNEL));
kfree(pages);
if (!vaddr) {
dev_warn(&pdev->dev, "paddr:%pa page_size:%pa failed to vmap\n",
&rmem->base, &rmem->size);
return 0;
}
/* Prepare for AOSP kernel info. backup */
rmem->priv = vaddr;
/* Backup vendor kernel info. */
all_info = (struct vendor_kernel_all_info *)(vaddr + offset);
memset(all_info, 0, sizeof(*all_info));
info = &all_info->info;
strscpy(info->uts_release, UTS_RELEASE, sizeof(info->uts_release));
update_vendor_kernel_all_info(all_info);
return 0;
}
static const struct of_device_id debug_snapshot_debug_kinfo_of_match[] = {
{ .compatible = "samsung,debug-snapshot-debug-kinfo" },
{},
};
MODULE_DEVICE_TABLE(of, debug_snapshot_debug_kinfo_of_match);
static struct platform_driver debug_snapshot_debug_kinfo_driver = {
.probe = debug_snapshot_debug_kinfo_probe,
.driver = {
.name = "debug-snapshot-debug-kinfo",
.of_match_table = of_match_ptr(debug_snapshot_debug_kinfo_of_match),
},
};
module_platform_driver(debug_snapshot_debug_kinfo_driver);
MODULE_DESCRIPTION("Debug Snapshot Debug Kinfo");
MODULE_LICENSE("GPL v2");