From b22838f67e39f6f9c482ea3d1f698aef8dc26ebe Mon Sep 17 00:00:00 2001 From: Simon Xue Date: Wed, 12 Feb 2025 12:07:06 +0800 Subject: [PATCH] soc: rockchip: add /proc/rk_zoneinfo/zoneinfo The dump zone information using the following two commands: 1. cat /proc/rk_zoneinfo/zoneinfo 2. cat /proc/rk_zoneinfo/zoneinfo > /data/data/1.txt NOTICE: dumping zone information should only be done during debugging. The dump zone information holds the spinlock of the zone, which can impact the performance of the memory subsystem. ==== ZONE & PAGE INFO (with page order) ==== Zone: DMA32 managed_pages: 952984 spanned_pages: 1048064 present_pages: 978432 Order: 0 | nr_free: 5 Migrate type 0 => (empty) Migrate type 1 => page: fffffffe000a3940 | PFN: 00010469 | phys_addr: 0x00028e5000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 0 Migrate type 1 => page: fffffffe0028d940 | PFN: 00041829 | phys_addr: 0x000a365000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 0 Migrate type 2 => (empty) Migrate type 3 => page: fffffffe004085c0 | PFN: 00066071 | phys_addr: 0x0010217000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 0 Migrate type 3 => page: fffffffe004089c0 | PFN: 00066087 | phys_addr: 0x0010227000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 0 Migrate type 3 => page: fffffffe00408ac0 | PFN: 00066091 | phys_addr: 0x001022b000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 0 Migrate type 4 => (empty) Migrate type 5 => (empty) Order: 1 | nr_free: 65 Migrate type 0 => (empty) Migrate type 1 => page: fffffffe000a3980 | PFN: 00010470 | phys_addr: 0x00028e6000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 1 Migrate type 1 => page: fffffffe0020d280 | PFN: 00033610 | phys_addr: 0x000834a000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 1 Migrate type 1 => page: fffffffe0028d980 | PFN: 00041830 | phys_addr: 0x000a366000 | flags: 0x0 | compound: 0 | node: 0 | zone: DMA32 | buddy_order: 1 Migrate type 2 => (empty) Change-Id: If9227fefaa79d744ca6dde123bd50f033d30c39c Signed-off-by: Simon Xue --- drivers/soc/rockchip/Kconfig | 6 + drivers/soc/rockchip/Makefile | 1 + drivers/soc/rockchip/rk_zoneinfo_procfs.c | 137 ++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 drivers/soc/rockchip/rk_zoneinfo_procfs.c diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig index e126daa6fafe..d2f9b3bea9e3 100644 --- a/drivers/soc/rockchip/Kconfig +++ b/drivers/soc/rockchip/Kconfig @@ -348,6 +348,12 @@ config RK_MEMBLOCK_PROCFS Extend memblock procfs to show size of each memblock, and shows the result of total size by KiB format. +config RK_ZONEINFO_PROCFS + bool "Zoneinfo procfs support" + depends on PROC_FS + help + Dump all zone information. + source "drivers/soc/rockchip/minidump/Kconfig" endmenu diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile index 9f75a77907ac..ad7e5c55610e 100644 --- a/drivers/soc/rockchip/Makefile +++ b/drivers/soc/rockchip/Makefile @@ -34,4 +34,5 @@ obj-$(CONFIG_ROCKCHIP_NPOR_POWERGOOD) += rockchip_npor_powergood.o obj-$(CONFIG_RK_CMA_PROCFS) += rk_cma_procfs.o obj-$(CONFIG_RK_DMABUF_PROCFS) += rk_dmabuf_procfs.o obj-$(CONFIG_RK_MEMBLOCK_PROCFS) += rk_memblock_procfs.o +obj-$(CONFIG_RK_ZONEINFO_PROCFS) += rk_zoneinfo_procfs.o obj-$(CONFIG_ROCKCHIP_MINIDUMP) += minidump/ diff --git a/drivers/soc/rockchip/rk_zoneinfo_procfs.c b/drivers/soc/rockchip/rk_zoneinfo_procfs.c new file mode 100644 index 000000000000..9b0e93f55b64 --- /dev/null +++ b/drivers/soc/rockchip/rk_zoneinfo_procfs.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This kernel module creates a procfs entry that prints + * detailed zone and page information, including the page's order if it + * is part of the buddy allocator (PageBuddy is set). It is updated for + * for_each_populated_zone(zone) iterates over all zones + * without referencing pgdat. For each zone and order, it shows: + * - free_area info by migrate type + * - each page in the free list, including: + * * page pointer + * * PFN (page frame number) + * * raw page flags + * * physical address + * * node ID + * * whether it's a compound page + * * the (buddy) order if PageBuddy is set + * + * Usage: + * cat /proc/rk_zoneinfo/zoneinfo > /data/data/1.txt + */ + +static int rk_zoneinfo_show(struct seq_file *m, void *v) +{ + struct zone *zone; + int order, type; + unsigned long flags; + + seq_puts(m, "==== ZONE & PAGE INFO (with page order) ====\n"); + + for_each_populated_zone(zone) { + seq_printf(m, "Zone: %s\n", zone->name); + seq_printf(m, " managed_pages: %lu\n", + atomic_long_read(&zone->managed_pages)); + seq_printf(m, " spanned_pages: %lu\n", zone->spanned_pages); + seq_printf(m, " present_pages: %lu\n\n", zone->present_pages); + + spin_lock_irqsave(&zone->lock, flags); + + /* For each order in this zone, we examine the free lists */ + for (order = 0; order < MAX_ORDER; order++) { + seq_printf(m, "\tOrder: %d | nr_free: %lu\n", + order, zone->free_area[order].nr_free); + + for (type = 0; type < MIGRATE_TYPES; type++) { + struct list_head *head = + &zone->free_area[order].free_list[type]; + struct page *page; + + if (list_empty(head)) { + seq_printf(m, "\t\tMigrate type %d => (empty)\n", type); + continue; + } + + list_for_each_entry(page, head, lru) { + unsigned long pfn = page_to_pfn(page); + unsigned int buddy_order = 0; + + if (PageBuddy(page)) + buddy_order = page_private(page); + + seq_printf( + m, + "\t\tMigrate type %d => page: %p | PFN: %08lu | phys_addr: 0x%010lx | flags: 0x%lx | compound: %d | node: %d | zone: %s | buddy_order: %u\n", + type, + page, + pfn, + (unsigned long)page_to_phys(page), + page->flags, + PageCompound(page), + page_to_nid(page), + zone->name, + buddy_order + ); + } + } + seq_puts(m, "\n"); + } + spin_unlock_irqrestore(&zone->lock, flags); + seq_puts(m, "----------------------------------------\n"); + } + + return 0; +} + +static int rk_zoneinfo_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rk_zoneinfo_show, NULL); +} + +static const struct proc_ops rk_zoneinfo_proc_fops = { + .proc_open = rk_zoneinfo_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int __init rk_zoneinfo_procfs_init(void) +{ + struct proc_dir_entry *entry; + + entry = proc_mkdir("rk_zoneinfo", NULL); + if (!entry) + return -ENOENT; + + if (!proc_create("zoneinfo", 0444, entry, &rk_zoneinfo_proc_fops)) + goto err; + + pr_info("rk_zoneinfo_procfs module loaded.\n"); + + return 0; +err: + remove_proc_subtree("rk_zoneinfo", NULL); + + return -ENOENT; +} + +module_init(rk_zoneinfo_procfs_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("xxm@rock-chips.com"); +MODULE_DESCRIPTION("iterating zones to show zone/page info and page order if buddy.");