]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/aim/ofw_machdep.c
This commit was generated by cvs2svn to compensate for changes in r150920,
[FreeBSD/FreeBSD.git] / sys / powerpc / aim / ofw_machdep.c
1 /*-
2  * Copyright (C) 1996 Wolfgang Solfrank.
3  * Copyright (C) 1996 TooLs GmbH.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by TooLs GmbH.
17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/systm.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <sys/fcntl.h>
43 #include <sys/malloc.h>
44 #include <sys/stat.h>
45
46 #include <net/ethernet.h>
47
48 #include <dev/ofw/openfirm.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_param.h>
52 #include <vm/vm_page.h>
53
54 #include <machine/powerpc.h>
55 #include <machine/ofw_machdep.h>
56 #include <powerpc/ofw/ofw_pci.h>
57
58 #define OFMEM_REGIONS   32
59 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3];
60 static struct mem_region OFfree[OFMEM_REGIONS + 3];
61
62 extern long     ofmsr;
63 extern struct   pmap ofw_pmap;
64 extern int      pmap_bootstrapped;
65 static int      (*ofwcall)(void *);
66
67 /*
68  * Memory region utilities: determine if two regions overlap,
69  * and merge two overlapping regions into one
70  */
71 static int
72 memr_overlap(struct mem_region *r1, struct mem_region *r2)
73 {
74         if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
75             (r2->mr_start + r2->mr_size) < r1->mr_start)
76                 return (FALSE);
77         
78         return (TRUE);  
79 }
80
81 static void
82 memr_merge(struct mem_region *from, struct mem_region *to)
83 {
84         int end;
85         end = imax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
86         to->mr_start = imin(from->mr_start, to->mr_start);
87         to->mr_size = end - to->mr_start;
88 }
89
90 /*
91  * This is called during powerpc_init, before the system is really initialized.
92  * It shall provide the total and the available regions of RAM.
93  * Both lists must have a zero-size entry as terminator.
94  * The available regions need not take the kernel into account, but needs
95  * to provide space for two additional entry beyond the terminating one.
96  */
97 void
98 mem_regions(struct mem_region **memp, int *memsz,
99                 struct mem_region **availp, int *availsz)
100 {
101         int phandle;
102         int asz, msz, fsz;
103         int i, j;
104         int still_merging;
105         
106         /*
107          * Get memory.
108          */
109         if ((phandle = OF_finddevice("/memory")) == -1
110             || (msz = OF_getprop(phandle, "reg",
111                           OFmem, sizeof OFmem[0] * OFMEM_REGIONS))
112                <= 0
113             || (asz = OF_getprop(phandle, "available",
114                           OFavail, sizeof OFavail[0] * OFMEM_REGIONS))
115                <= 0)
116                 panic("no memory?");
117         *memp = OFmem;
118         *memsz = msz / sizeof(struct mem_region);
119
120         /*
121          * OFavail may have overlapping regions - collapse these
122          * and copy out remaining regions to OFfree
123          */
124         asz /= sizeof(struct mem_region);
125         do {
126                 still_merging = FALSE;
127                 for (i = 0; i < asz; i++) {
128                         if (OFavail[i].mr_size == 0)
129                                 continue;
130                         for (j = i+1; j < asz; j++) {
131                                 if (OFavail[j].mr_size == 0)
132                                         continue;
133                                 if (memr_overlap(&OFavail[j], &OFavail[i])) {
134                                         memr_merge(&OFavail[j], &OFavail[i]);
135                                         /* mark inactive */
136                                         OFavail[j].mr_size = 0;
137                                         still_merging = TRUE;
138                                 }
139                         }
140                 }
141         } while (still_merging == TRUE);
142
143         /* evict inactive ranges */
144         for (i = 0, fsz = 0; i < asz; i++) {
145                 if (OFavail[i].mr_size != 0) {
146                         OFfree[fsz] = OFavail[i];
147                         fsz++;
148                 }
149         }
150
151         *availp = OFfree;
152         *availsz = fsz;
153 }
154
155 void
156 set_openfirm_callback(int (*openfirm)(void *))
157 {
158
159         ofwcall = openfirm;
160 }
161
162 int
163 openfirmware(void *args)
164 {
165         long    oldmsr;
166         int     result;
167         u_int   srsave[16];
168         u_int   i;
169
170         __asm __volatile(       "\t"
171                 "sync\n\t"
172                 "mfmsr  %0\n\t"
173                 "mtmsr  %1\n\t"
174                 "isync\n"
175                 : "=r" (oldmsr)
176                 : "r" (ofmsr)
177         );
178
179         if (pmap_bootstrapped) {
180                 /*
181                  * Swap the kernel's address space with Open Firmware's
182                  */
183                 for (i = 0; i < 16; i++) {
184                         srsave[i] = mfsrin(i << ADDR_SR_SHFT);
185                         mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
186                 }
187
188                 /*
189                  * Clear battable[] translations
190                  */
191                 __asm __volatile("mtdbatu 2, %0\n"
192                                  "mtdbatu 3, %0" : : "r" (0));
193                 isync();
194         }
195         
196         result = ofwcall(args);
197
198         if (pmap_bootstrapped) {
199                 /*
200                  * Restore the kernel's addr space. The isync() doesn;t
201                  * work outside the loop unless mtsrin() is open-coded
202                  * in an asm statement :(
203                  */
204                 for (i = 0; i < 16; i++) {
205                         mtsrin(i << ADDR_SR_SHFT, srsave[i]);
206                         isync();
207                 }
208         }
209
210         __asm(  "\t"
211                 "mtmsr  %0\n\t"
212                 "isync\n"
213                 : : "r" (oldmsr)
214         );
215
216         return (result);
217 }
218
219 void
220 OF_halt()
221 {
222         int retval;     /* dummy, this may not be needed */
223
224         OF_interpret("shut-down", 1, &retval);
225         for (;;);       /* just in case */
226 }
227
228 void
229 OF_reboot()
230 {
231         int retval;     /* dummy, this may not be needed */
232
233         OF_interpret("reset-all", 1, &retval);
234         for (;;);       /* just in case */
235 }
236
237 void
238 OF_getetheraddr(device_t dev, u_char *addr)
239 {
240         phandle_t       node;
241
242         node = ofw_pci_find_node(dev);
243         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
244 }
245
246 int
247 mem_valid(vm_offset_t addr, int len)
248 {
249         int i;
250
251         for (i = 0; i < OFMEM_REGIONS; i++)
252                 if ((addr >= OFmem[i].mr_start) 
253                     && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
254                         return (0);
255
256         return (EFAULT);
257 }