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)  * nvs.c - Routines for saving and restoring ACPI NVS memory region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2008-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include "internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) /* ACPI NVS regions, APEI may use it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) struct nvs_region {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	__u64 phys_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	__u64 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	struct list_head node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) static LIST_HEAD(nvs_region_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #ifdef CONFIG_ACPI_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) static int suspend_nvs_register(unsigned long start, unsigned long size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) static inline int suspend_nvs_register(unsigned long a, unsigned long b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) int acpi_nvs_register(__u64 start, __u64 size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	struct nvs_region *region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	region = kmalloc(sizeof(*region), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	if (!region)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	region->phys_start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	region->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	list_add_tail(&region->node, &nvs_region_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	return suspend_nvs_register(start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 			     void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	struct nvs_region *region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	list_for_each_entry(region, &nvs_region_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		rc = func(region->phys_start, region->size, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 			return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) }
^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) #ifdef CONFIG_ACPI_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68)  * Platforms, like ACPI, may want us to save some memory used by them during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69)  * suspend and to restore the contents of this memory during the subsequent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)  * resume.  The code below implements a mechanism allowing us to do that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) struct nvs_page {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	unsigned long phys_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	unsigned int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	void *kaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	void *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	bool unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	struct list_head node;
^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 LIST_HEAD(nvs_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)  *	suspend_nvs_register - register platform NVS memory region to save
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)  *	@start - physical address of the region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87)  *	@size - size of the region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89)  *	The NVS region need not be page-aligned (both ends) and we arrange
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)  *	things so that the data from page-aligned addresses in this region will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91)  *	be copied into separate RAM pages.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) static int suspend_nvs_register(unsigned long start, unsigned long size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	struct nvs_page *entry, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	pr_info("PM: Registering ACPI NVS region [mem %#010lx-%#010lx] (%ld bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		start, start + size - 1, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	while (size > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		unsigned int nr_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		entry = kzalloc(sizeof(struct nvs_page), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		if (!entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 			goto Error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		list_add_tail(&entry->node, &nvs_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 		entry->phys_start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		nr_bytes = PAGE_SIZE - (start & ~PAGE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		entry->size = (size < nr_bytes) ? size : nr_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		start += entry->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		size -= entry->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)  Error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	list_for_each_entry_safe(entry, next, &nvs_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		list_del(&entry->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		kfree(entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)  *	suspend_nvs_free - free data pages allocated for saving NVS regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) void suspend_nvs_free(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	struct nvs_page *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	list_for_each_entry(entry, &nvs_list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		if (entry->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			free_page((unsigned long)entry->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			entry->data = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			if (entry->kaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 				if (entry->unmap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 					iounmap(entry->kaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 					entry->unmap = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 				} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 					acpi_os_unmap_iomem(entry->kaddr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 							    entry->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 				entry->kaddr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)  *	suspend_nvs_alloc - allocate memory necessary for saving NVS regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) int suspend_nvs_alloc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	struct nvs_page *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	list_for_each_entry(entry, &nvs_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		entry->data = (void *)__get_free_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		if (!entry->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 			suspend_nvs_free();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 			return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)  *	suspend_nvs_save - save NVS memory regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int suspend_nvs_save(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	struct nvs_page *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	printk(KERN_INFO "PM: Saving platform NVS memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	list_for_each_entry(entry, &nvs_list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		if (entry->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 			unsigned long phys = entry->phys_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			unsigned int size = entry->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			entry->kaddr = acpi_os_get_iomem(phys, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 			if (!entry->kaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 				entry->kaddr = acpi_os_ioremap(phys, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 				entry->unmap = !!entry->kaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			if (!entry->kaddr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 				suspend_nvs_free();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 				return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			memcpy(entry->data, entry->kaddr, entry->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)  *	suspend_nvs_restore - restore NVS memory regions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)  *	This function is going to be called with interrupts disabled, so it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)  *	cannot iounmap the virtual addresses used to access the NVS region.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) void suspend_nvs_restore(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	struct nvs_page *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	printk(KERN_INFO "PM: Restoring platform NVS memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	list_for_each_entry(entry, &nvs_list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		if (entry->data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			memcpy(entry->kaddr, entry->data, entry->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #endif