Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * mm/percpu-km.c - kernel memory based chunk allocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2010		SUSE Linux Products GmbH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2010		Tejun Heo <tj@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Chunks are allocated as a contiguous kernel memory using gfp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * allocation.  This is to be used on nommu architectures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * To use percpu-km,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * - define CONFIG_NEED_PER_CPU_KM from the arch Kconfig.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  * - CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK must not be defined.  It's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *   not compatible with PER_CPU_KM.  EMBED_FIRST_CHUNK should work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *   fine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * - NUMA is not supported.  When setting up the first chunk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  *   @cpu_distance_fn should be NULL or report all CPUs to be nearer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *   than or at LOCAL_DISTANCE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * - It's best if the chunk size is power of two multiple of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  *   PAGE_SIZE.  Because each chunk is allocated as a contiguous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *   kernel memory block using alloc_pages(), memory will be wasted if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  *   chunk size is not aligned.  percpu-km code will whine about it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #if defined(CONFIG_SMP) && defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #error "contiguous percpu allocation is incompatible with paged first chunk"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 			       int page_start, int page_end, gfp_t gfp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 				  int page_start, int page_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	/* nada */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static struct pcpu_chunk *pcpu_create_chunk(enum pcpu_chunk_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 					    gfp_t gfp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	struct pcpu_chunk *chunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	struct page *pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	chunk = pcpu_alloc_chunk(type, gfp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	if (!chunk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	pages = alloc_pages(gfp, order_base_2(nr_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	if (!pages) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		pcpu_free_chunk(chunk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	for (i = 0; i < nr_pages; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		pcpu_set_page_chunk(nth_page(pages, i), chunk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	chunk->data = pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	chunk->base_addr = page_address(pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	spin_lock_irqsave(&pcpu_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	pcpu_chunk_populated(chunk, 0, nr_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	spin_unlock_irqrestore(&pcpu_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	pcpu_stats_chunk_alloc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	trace_percpu_create_chunk(chunk->base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	return chunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static void pcpu_destroy_chunk(struct pcpu_chunk *chunk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	if (!chunk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	pcpu_stats_chunk_dealloc();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	trace_percpu_destroy_chunk(chunk->base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	if (chunk->data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		__free_pages(chunk->data, order_base_2(nr_pages));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	pcpu_free_chunk(chunk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static struct page *pcpu_addr_to_page(void *addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	return virt_to_page(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	size_t nr_pages, alloc_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	/* all units must be in a single group */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	if (ai->nr_groups != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		pr_crit("can't handle more than one group\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	nr_pages = (ai->groups[0].nr_units * ai->unit_size) >> PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	alloc_pages = roundup_pow_of_two(nr_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	if (alloc_pages > nr_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		pr_warn("wasting %zu pages per chunk\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 			alloc_pages - nr_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }