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