1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This file contains platform-dependent MMU support routines,
28  * suitable for mmu methods with 2-cell physical addresses.
29  * Use of these routines makes the caller platform-dependent,
30  * since the caller assumes knowledge of the physical layout of
31  * the machines address space.  Generic programs should use the
32  * standard client interface memory allocators.
33  */
34 
35 #include <sys/promif.h>
36 #include <sys/promimpl.h>
37 
38 ihandle_t
prom_mmu_ihandle(void)39 prom_mmu_ihandle(void)
40 {
41 	static ihandle_t immu;
42 
43 	if (immu != (ihandle_t)0)
44 		return (immu);
45 
46 	if (prom_getproplen(prom_chosennode(), "mmu") != sizeof (ihandle_t))
47 		return (immu = (ihandle_t)-1);
48 
49 	(void) prom_getprop(prom_chosennode(), "mmu", (caddr_t)(&immu));
50 	return (immu);
51 }
52 
53 /*
54  * prom_map_phys:
55  *
56  * Create an MMU mapping for a given physical address to a given virtual
57  * address. The given resources are assumed to be owned by the caller,
58  * and are *not* removed from any free lists.
59  *
60  * This routine is suitable for mapping a 2-cell physical address.
61  */
62 
63 int
prom_map_phys(int mode,size_t size,caddr_t virt,unsigned long long physaddr)64 prom_map_phys(int mode, size_t size, caddr_t virt, unsigned long long physaddr)
65 {
66 	cell_t ci[11];
67 	int rv;
68 	ihandle_t immu = prom_mmu_ihandle();
69 
70 	if ((immu == (ihandle_t)-1))
71 		return (-1);
72 
73 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
74 	ci[1] = (cell_t)7;			/* #argument cells */
75 	ci[2] = (cell_t)1;			/* #result cells */
76 	ci[3] = p1275_ptr2cell("map");		/* Arg1: method name */
77 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
78 	ci[5] = p1275_int2cell(mode);		/* Arg3: SA1: mode */
79 	ci[6] = p1275_size2cell(size);		/* Arg4: SA2: size */
80 	ci[7] = p1275_ptr2cell(virt);		/* Arg5: SA3: virt */
81 	ci[8] = p1275_ull2cell_high(physaddr);	/* Arg6: SA4: phys.hi */
82 	ci[9] = p1275_ull2cell_low(physaddr);	/* Arg7: SA5: phys.low */
83 
84 	promif_preprom();
85 	rv = p1275_cif_handler(&ci);
86 	promif_postprom();
87 
88 	if (rv != 0)
89 		return (-1);
90 	if (ci[10] != 0)			/* Res1: Catch result */
91 		return (-1);
92 	return (0);
93 }
94 
95 void
prom_unmap_phys(size_t size,caddr_t virt)96 prom_unmap_phys(size_t size, caddr_t virt)
97 {
98 	(void) prom_unmap_virt(size, virt);
99 }
100 
101 /*
102  * Allocate aligned or unaligned virtual address space, unmapped.
103  */
104 caddr_t
prom_allocate_virt(uint_t align,size_t size)105 prom_allocate_virt(uint_t align, size_t size)
106 {
107 	cell_t ci[9];
108 	int rv;
109 	ihandle_t immu = prom_mmu_ihandle();
110 
111 	if ((immu == (ihandle_t)-1))
112 		return ((caddr_t)-1);
113 
114 	if (align == 0)
115 		align = 1;
116 
117 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
118 	ci[1] = (cell_t)4;			/* #argument cells */
119 	ci[2] = (cell_t)2;			/* #result cells */
120 	ci[3] = p1275_ptr2cell("claim");	/* Arg1: Method name */
121 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
122 	ci[5] = p1275_uint2cell(align);		/* Arg3: SA1: align */
123 	ci[6] = p1275_size2cell(size);		/* Arg4: SA2: size */
124 
125 	promif_preprom();
126 	rv = p1275_cif_handler(&ci);
127 	promif_postprom();
128 
129 	if (rv != 0)
130 		return ((caddr_t)-1);
131 	if (ci[7] != 0)				/* Res1: Catch result */
132 		return ((caddr_t)-1);
133 	return (p1275_cell2ptr(ci[8]));		/* Res2: SR1: base */
134 }
135 
136 /*
137  * Claim a region of virtual address space, unmapped.
138  */
139 caddr_t
prom_claim_virt(size_t size,caddr_t virt)140 prom_claim_virt(size_t size, caddr_t virt)
141 {
142 	cell_t ci[10];
143 	int rv;
144 	ihandle_t immu = prom_mmu_ihandle();
145 
146 	if ((immu == (ihandle_t)-1))
147 		return ((caddr_t)-1);
148 
149 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
150 	ci[1] = (cell_t)5;			/* #argument cells */
151 	ci[2] = (cell_t)2;			/* #result cells */
152 	ci[3] = p1275_ptr2cell("claim");	/* Arg1: Method name */
153 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
154 	ci[5] = (cell_t)0;			/* Arg3: align */
155 	ci[6] = p1275_size2cell(size);		/* Arg4: length */
156 	ci[7] = p1275_ptr2cell(virt);		/* Arg5: virt */
157 
158 	promif_preprom();
159 	rv = p1275_cif_handler(&ci);
160 	promif_postprom();
161 
162 	if (rv != 0)
163 		return ((caddr_t)-1);
164 	if (ci[8] != 0)				/* Res1: Catch result */
165 		return ((caddr_t)-1);
166 	return (p1275_cell2ptr(ci[9]));		/* Res2: base */
167 }
168 
169 /*
170  * Free virtual address resource (no unmapping is done).
171  */
172 void
prom_free_virt(size_t size,caddr_t virt)173 prom_free_virt(size_t size, caddr_t virt)
174 {
175 	cell_t ci[7];
176 	ihandle_t immu = prom_mmu_ihandle();
177 
178 	if ((immu == (ihandle_t)-1))
179 		return;
180 
181 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
182 	ci[1] = (cell_t)4;			/* #argument cells */
183 	ci[2] = (cell_t)0;			/* #return cells */
184 	ci[3] = p1275_ptr2cell("release");	/* Arg1: Method name */
185 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
186 	ci[5] = p1275_size2cell(size);		/* Arg3: length */
187 	ci[6] = p1275_ptr2cell(virt);		/* Arg4: virt */
188 
189 	promif_preprom();
190 	(void) p1275_cif_handler(&ci);
191 	promif_postprom();
192 }
193 
194 /*
195  * Un-map virtual address. Does not free underlying resources.
196  */
197 void
prom_unmap_virt(size_t size,caddr_t virt)198 prom_unmap_virt(size_t size, caddr_t virt)
199 {
200 	cell_t ci[7];
201 	ihandle_t immu = prom_mmu_ihandle();
202 
203 	if ((immu == (ihandle_t)-1))
204 		return;
205 
206 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
207 	ci[1] = (cell_t)4;			/* #argument cells */
208 	ci[2] = (cell_t)0;			/* #result cells */
209 	ci[3] = p1275_ptr2cell("unmap");	/* Arg1: Method name */
210 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
211 	ci[5] = p1275_size2cell(size);		/* Arg3: SA1: size */
212 	ci[6] = p1275_ptr2cell(virt);		/* Arg4: SA2: virt */
213 
214 	promif_preprom();
215 	(void) p1275_cif_handler(&ci);
216 	promif_postprom();
217 }
218 
219 static pnode_t
prom_mmu_phandle(void)220 prom_mmu_phandle(void)
221 {
222 	static pnode_t pmmu = 0;
223 
224 	if (pmmu == (pnode_t)0)  {
225 		ihandle_t ih;
226 
227 		if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1)
228 			prom_panic("Can't get mmu ihandle");
229 		pmmu = prom_getphandle(ih);
230 	}
231 	return (pmmu);
232 }
233 
234 
235 int
prom_virt_avail_len(void)236 prom_virt_avail_len(void)
237 {
238 	return (prom_getproplen(prom_mmu_phandle(), "available"));
239 }
240 
241 int
prom_virt_avail(caddr_t prop)242 prom_virt_avail(caddr_t prop)
243 {
244 	return (prom_getprop(prom_mmu_phandle(), "available", prop));
245 }
246 
247 /*
248  * Translate virtual address to physical address.
249  * Returns 0: Success; Non-zero: failure.
250  * Returns *phys_hi, *phys_lo and *mode only if successful.
251  */
252 int
prom_translate_virt(caddr_t virt,int * valid,unsigned long long * physaddr,int * mode)253 prom_translate_virt(caddr_t virt, int *valid,
254 		unsigned long long *physaddr, int *mode)
255 {
256 	cell_t ci[11];
257 	int rv;
258 	ihandle_t immu = prom_mmu_ihandle();
259 
260 	*valid = 0;
261 
262 	if ((immu == (ihandle_t)-1))
263 		return (-1);
264 
265 	ci[0] = p1275_ptr2cell("call-method");	/* Service name */
266 	ci[1] = (cell_t)3;			/* #argument cells */
267 	ci[2] = (cell_t)5;			/* #result cells */
268 	ci[3] = p1275_ptr2cell("translate");	/* Arg1: Method name */
269 	ci[4] = p1275_ihandle2cell(immu);	/* Arg2: mmu ihandle */
270 	ci[5] = p1275_ptr2cell(virt);		/* Arg3: virt */
271 	ci[6] = 0;				/* Res1: catch-resule */
272 	ci[7] = 0;				/* Res2: sr1: valid */
273 
274 	promif_preprom();
275 	rv = p1275_cif_handler(&ci);
276 	promif_postprom();
277 
278 	if (rv == -1)				/* Did the call fail ? */
279 		return (-1);
280 	if (ci[6] != 0)				/* Catch result */
281 		return (-1);
282 
283 	if (p1275_cell2int(ci[7]) != -1)	/* Valid results ? */
284 		return (0);
285 
286 	*mode = p1275_cell2int(ci[8]);		/* Res3: sr2: mode, if valid */
287 	*physaddr = p1275_cells2ull(ci[9], ci[10]);
288 				/* Res4: sr3: phys-hi ... Res5: sr4: phys-lo */
289 	*valid = -1;				/* Indicate valid result */
290 	return (0);
291 }
292