162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/mm/mmzone.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * management codes for pgdats, zones and page flags
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/stddef.h>
1062306a36Sopenharmony_ci#include <linux/mm.h>
1162306a36Sopenharmony_ci#include <linux/mmzone.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct pglist_data *first_online_pgdat(void)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	return NODE_DATA(first_online_node);
1662306a36Sopenharmony_ci}
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct pglist_data *next_online_pgdat(struct pglist_data *pgdat)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	int nid = next_online_node(pgdat->node_id);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (nid == MAX_NUMNODES)
2362306a36Sopenharmony_ci		return NULL;
2462306a36Sopenharmony_ci	return NODE_DATA(nid);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * next_zone - helper magic for for_each_zone()
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_cistruct zone *next_zone(struct zone *zone)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	pg_data_t *pgdat = zone->zone_pgdat;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (zone < pgdat->node_zones + MAX_NR_ZONES - 1)
3562306a36Sopenharmony_ci		zone++;
3662306a36Sopenharmony_ci	else {
3762306a36Sopenharmony_ci		pgdat = next_online_pgdat(pgdat);
3862306a36Sopenharmony_ci		if (pgdat)
3962306a36Sopenharmony_ci			zone = pgdat->node_zones;
4062306a36Sopenharmony_ci		else
4162306a36Sopenharmony_ci			zone = NULL;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci	return zone;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci#ifdef CONFIG_NUMA
4962306a36Sopenharmony_ci	return node_isset(zonelist_node_idx(zref), *nodes);
5062306a36Sopenharmony_ci#else
5162306a36Sopenharmony_ci	return 1;
5262306a36Sopenharmony_ci#endif /* CONFIG_NUMA */
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* Returns the next zone at or below highest_zoneidx in a zonelist */
5662306a36Sopenharmony_cistruct zoneref *__next_zones_zonelist(struct zoneref *z,
5762306a36Sopenharmony_ci					enum zone_type highest_zoneidx,
5862306a36Sopenharmony_ci					nodemask_t *nodes)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	/*
6162306a36Sopenharmony_ci	 * Find the next suitable zone to use for the allocation.
6262306a36Sopenharmony_ci	 * Only filter based on nodemask if it's set
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci	if (unlikely(nodes == NULL))
6562306a36Sopenharmony_ci		while (zonelist_zone_idx(z) > highest_zoneidx)
6662306a36Sopenharmony_ci			z++;
6762306a36Sopenharmony_ci	else
6862306a36Sopenharmony_ci		while (zonelist_zone_idx(z) > highest_zoneidx ||
6962306a36Sopenharmony_ci				(z->zone && !zref_in_nodemask(z, nodes)))
7062306a36Sopenharmony_ci			z++;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return z;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_civoid lruvec_init(struct lruvec *lruvec)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	enum lru_list lru;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	memset(lruvec, 0, sizeof(struct lruvec));
8062306a36Sopenharmony_ci	spin_lock_init(&lruvec->lru_lock);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	for_each_lru(lru)
8362306a36Sopenharmony_ci		INIT_LIST_HEAD(&lruvec->lists[lru]);
8462306a36Sopenharmony_ci	/*
8562306a36Sopenharmony_ci	 * The "Unevictable LRU" is imaginary: though its size is maintained,
8662306a36Sopenharmony_ci	 * it is never scanned, and unevictable pages are not threaded on it
8762306a36Sopenharmony_ci	 * (so that their lru fields can be reused to hold mlock_count).
8862306a36Sopenharmony_ci	 * Poison its list head, so that any operations on it would crash.
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	list_del(&lruvec->lists[LRU_UNEVICTABLE]);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	lru_gen_init_lruvec(lruvec);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS)
9662306a36Sopenharmony_ciint page_cpupid_xchg_last(struct page *page, int cpupid)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	unsigned long old_flags, flags;
9962306a36Sopenharmony_ci	int last_cpupid;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	old_flags = READ_ONCE(page->flags);
10262306a36Sopenharmony_ci	do {
10362306a36Sopenharmony_ci		flags = old_flags;
10462306a36Sopenharmony_ci		last_cpupid = (flags >> LAST_CPUPID_PGSHIFT) & LAST_CPUPID_MASK;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		flags &= ~(LAST_CPUPID_MASK << LAST_CPUPID_PGSHIFT);
10762306a36Sopenharmony_ci		flags |= (cpupid & LAST_CPUPID_MASK) << LAST_CPUPID_PGSHIFT;
10862306a36Sopenharmony_ci	} while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return last_cpupid;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci#endif
113