1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * memory.c: PROM library functions for acquiring/using memory descriptors 4 * given to us from the ARCS firmware. 5 * 6 * Copyright (C) 1996 by David S. Miller 7 * Copyright (C) 1999, 2000, 2001 by Ralf Baechle 8 * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. 9 * 10 * PROM library functions for acquiring/using memory descriptors given to us 11 * from the ARCS firmware. This is only used when CONFIG_ARC_MEMORY is set 12 * because on some machines like SGI IP27 the ARC memory configuration data 13 * completely bogus and alternate easier to use mechanisms are available. 14 */ 15 #include <linux/init.h> 16 #include <linux/kernel.h> 17 #include <linux/types.h> 18 #include <linux/sched.h> 19 #include <linux/mm.h> 20 #include <linux/memblock.h> 21 #include <linux/swap.h> 22 23 #include <asm/sgialib.h> 24 #include <asm/page.h> 25 #include <asm/pgtable.h> 26 #include <asm/bootinfo.h> 27 28 #undef DEBUG 29 30 #define MAX_PROM_MEM 5 31 static phys_addr_t prom_mem_base[MAX_PROM_MEM] __initdata; 32 static phys_addr_t prom_mem_size[MAX_PROM_MEM] __initdata; 33 static unsigned int nr_prom_mem __initdata; 34 35 /* 36 * For ARC firmware memory functions the unit of meassuring memory is always 37 * a 4k page of memory 38 */ 39 #define ARC_PAGE_SHIFT 12 40 41 struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) 42 { 43 return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); 44 } 45 46 #ifdef DEBUG /* convenient for debugging */ 47 static char *arcs_mtypes[8] = { 48 "Exception Block", 49 "ARCS Romvec Page", 50 "Free/Contig RAM", 51 "Generic Free RAM", 52 "Bad Memory", 53 "Standalone Program Pages", 54 "ARCS Temp Storage Area", 55 "ARCS Permanent Storage Area" 56 }; 57 58 static char *arc_mtypes[8] = { 59 "Exception Block", 60 "SystemParameterBlock", 61 "FreeMemory", 62 "Bad Memory", 63 "LoadedProgram", 64 "FirmwareTemporary", 65 "FirmwarePermanent", 66 "FreeContiguous" 67 }; 68 #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] \ 69 : arc_mtypes[a.arc] 70 #endif 71 72 static inline int memtype_classify_arcs(union linux_memtypes type) 73 { 74 switch (type.arcs) { 75 case arcs_fcontig: 76 case arcs_free: 77 return BOOT_MEM_RAM; 78 case arcs_atmp: 79 return BOOT_MEM_ROM_DATA; 80 case arcs_eblock: 81 case arcs_rvpage: 82 case arcs_bmem: 83 case arcs_prog: 84 case arcs_aperm: 85 return BOOT_MEM_RESERVED; 86 default: 87 BUG(); 88 } 89 while(1); /* Nuke warning. */ 90 } 91 92 static inline int memtype_classify_arc(union linux_memtypes type) 93 { 94 switch (type.arc) { 95 case arc_free: 96 case arc_fcontig: 97 return BOOT_MEM_RAM; 98 case arc_atmp: 99 return BOOT_MEM_ROM_DATA; 100 case arc_eblock: 101 case arc_rvpage: 102 case arc_bmem: 103 case arc_prog: 104 case arc_aperm: 105 return BOOT_MEM_RESERVED; 106 default: 107 BUG(); 108 } 109 while(1); /* Nuke warning. */ 110 } 111 112 static int __init prom_memtype_classify(union linux_memtypes type) 113 { 114 if (prom_flags & PROM_FLAG_ARCS) /* SGI is ``different'' ... */ 115 return memtype_classify_arcs(type); 116 117 return memtype_classify_arc(type); 118 } 119 120 void __weak __init prom_meminit(void) 121 { 122 struct linux_mdesc *p; 123 124 #ifdef DEBUG 125 int i = 0; 126 127 printk("ARCS MEMORY DESCRIPTOR dump:\n"); 128 p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); 129 while(p) { 130 printk("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", 131 i, p, p->base, p->pages, mtypes(p->type)); 132 p = ArcGetMemoryDescriptor(p); 133 i++; 134 } 135 #endif 136 137 nr_prom_mem = 0; 138 p = PROM_NULL_MDESC; 139 while ((p = ArcGetMemoryDescriptor(p))) { 140 unsigned long base, size; 141 long type; 142 143 base = p->base << ARC_PAGE_SHIFT; 144 size = p->pages << ARC_PAGE_SHIFT; 145 type = prom_memtype_classify(p->type); 146 147 add_memory_region(base, size, type); 148 149 if (type == BOOT_MEM_ROM_DATA) { 150 if (nr_prom_mem >= 5) { 151 pr_err("Too many ROM DATA regions"); 152 continue; 153 } 154 prom_mem_base[nr_prom_mem] = base; 155 prom_mem_size[nr_prom_mem] = size; 156 nr_prom_mem++; 157 } 158 } 159 } 160 161 void __weak __init prom_cleanup(void) 162 { 163 } 164 165 void __weak __init prom_free_prom_memory(void) 166 { 167 int i; 168 169 if (prom_flags & PROM_FLAG_DONT_FREE_TEMP) 170 return; 171 172 for (i = 0; i < nr_prom_mem; i++) { 173 free_init_pages("prom memory", 174 prom_mem_base[i], prom_mem_base[i] + prom_mem_size[i]); 175 } 176 /* 177 * at this point it isn't safe to call PROM functions 178 * give platforms a way to do PROM cleanups 179 */ 180 prom_cleanup(); 181 } 182