blob: cef4746ecfcdca01f06868fa39182e767496b4c4 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2018-2020 Oplus. All rights reserved.
*/
#include <linux/stddef.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/interrupt.h>
#include <linux/pagemap.h>
#include <linux/jiffies.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/kasan.h>
#include <linux/module.h>
#include <linux/suspend.h>
#include <linux/pagevec.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/oom.h>
#include <linux/topology.h>
#include <linux/sysctl.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/memory_hotplug.h>
#include <linux/nodemask.h>
#include <linux/vmalloc.h>
#include <linux/vmstat.h>
#include <linux/mempolicy.h>
#include <linux/memremap.h>
#include <linux/stop_machine.h>
#include <linux/sort.h>
#include <linux/pfn.h>
#include <linux/backing-dev.h>
#include <linux/fault-inject.h>
#include <linux/page-isolation.h>
#include <linux/page_ext.h>
#include <linux/debugobjects.h>
#include <linux/kmemleak.h>
#include <linux/compaction.h>
#include <trace/events/kmem.h>
#include <trace/events/oom.h>
#include <linux/prefetch.h>
#include <linux/mm_inline.h>
#include <linux/migrate.h>
#include <linux/hugetlb.h>
#include <linux/sched/rt.h>
#include <linux/sched/mm.h>
#include <linux/page_owner.h>
#include <linux/kthread.h>
#include <linux/memcontrol.h>
#include <linux/ftrace.h>
#include <linux/lockdep.h>
#include <linux/nmi.h>
#include <linux/psi.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/vmstat.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/math64.h>
#include <linux/writeback.h>
#include "internal.h"
#ifdef VENDOR_EDIT
#include "multi_freearea.h"
#endif
#include "internal.h"
static unsigned int show_order = 0;
#define SHOW_ALL (11)
static char * const zone_names[MAX_NR_ZONES] = {
#ifdef CONFIG_ZONE_DMA
"DMA",
#endif
#ifdef CONFIG_ZONE_DMA32
"DMA32",
#endif
"Normal",
#ifdef CONFIG_HIGHMEM
"HighMem",
#endif
"Movable",
#ifdef CONFIG_ZONE_DEVICE
"Device",
#endif
};
static int proc_free_area_show(struct seq_file *m, void *p)
{
unsigned int order, t, flc;
pg_data_t *pgdat = NODE_DATA(0);
struct page *page;
int zone_type;
for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
struct zone *zone = &pgdat->node_zones[zone_type];
if (!managed_zone(zone)) {
continue;
}
seq_printf(m, "---------------------------------------------------------------------------------------------------------------\n");
seq_printf(m, "zone_name = %s, show_order = %u\n", zone_names[zone_type], show_order);
for (flc = 0; flc < FREE_AREA_COUNTS; flc++)
seq_printf(m, "[%d]: label = %lu, segment = %lu\n", flc, zone->zone_label[flc].label, zone->zone_label[flc].segment);
seq_printf(m, "\n---------------------------------------------------------------------------------------------------------------\n");
for (flc = 0; flc < FREE_AREA_COUNTS; flc++) {
seq_printf(m, "flc = %u\n", flc);
for_each_migratetype_order(order, t) {
if (order == show_order || show_order == SHOW_ALL) {
seq_printf(m, "order = %u, mt = %u\n", order, t);
list_for_each_entry(page, &(zone->free_area[flc][order].free_list[t]), lru) {
seq_printf(m, "%lu\t", page_to_pfn(page));
}
seq_printf(m, "\n");
}
}
}
}
return 0;
}
static ssize_t proc_free_area_write(struct file *file, const char __user *buff, size_t len, loff_t *ppos)
{
char write_data[16] = {0};
int ret = 0;
if (copy_from_user(&write_data, buff, len)) {
return -EFAULT;
}
ret = kstrtouint(write_data, 10, &show_order);
return len;
}
static int proc_free_area_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_free_area_show, NULL);
}
const struct file_operations proc_free_area_fops = {
.open = proc_free_area_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = proc_free_area_write,
};
void list_sort_add(struct page *page, struct zone *zone, unsigned int order, int mt)
{
struct list_head *list = &(zone->free_area[0][order].free_list[mt]);
unsigned long pfn = 0, segment = 0;
int i = 0;
pfn = page_to_pfn(page);
if (unlikely(pfn > zone->zone_label[FREE_AREA_COUNTS - 1].label)) {
list = &(zone->free_area[FREE_AREA_COUNTS - 1][order].free_list[mt]);
segment = zone->zone_label[FREE_AREA_COUNTS - 1].segment;
goto add_page;
}
for (i = 0; i < FREE_AREA_COUNTS; i++) {
if (pfn <= zone->zone_label[i].label) {
list = &(zone->free_area[i][order].free_list[mt]);
segment = zone->zone_label[i].segment;
break;
}
}
add_page:
if (pfn >= segment)
list_add_tail(&page->lru, list);
else
list_add(&page->lru, list);
}
int page_to_flc(struct page *page)
{
struct zone *zone = page_zone(page);
unsigned long pfn = page_to_pfn(page);
int flc = 0;
if (unlikely(pfn > zone->zone_label[FREE_AREA_COUNTS - 1].label))
return FREE_AREA_COUNTS - 1;
for (flc = 0; flc < FREE_AREA_COUNTS; flc++) {
if (pfn <= zone->zone_label[flc].label)
return flc;
}
return flc;
}
void ajust_zone_label(struct zone *zone)
{
int i;
unsigned long prev_base;
for (i = 0; i < FREE_AREA_COUNTS; i++) {
zone->zone_label[i].label = zone->zone_start_pfn + zone->spanned_pages * (i + 1) / FREE_AREA_COUNTS;
}
for (i = 0; i < FREE_AREA_COUNTS; i++) {
if (i == 0)
prev_base = zone->zone_start_pfn;
else
prev_base = zone->zone_label[i - 1].label;
zone->zone_label[i].segment = prev_base +
((zone->zone_label[i].label - prev_base) >> 1);
}
}
unsigned int ajust_flc(unsigned int current_flc, unsigned int order)
{
/* when alloc_order >= HIGH_ORDER_TO_FLC,
* we like to alloc in free_area: 4->3->2->1
*/
if (order >= HIGH_ORDER_TO_FLC)
return (FREE_AREA_COUNTS - 1 - current_flc);
return current_flc;
}