xref: /OK3568_Linux_fs/kernel/arch/mips/fw/arc/memory.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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