3
Copyright (C) 1995, 1996 David S. Miller
4
1996, 1998, 1999 Jakub Jelinek
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
24
#define INITRD_VIRT_ADDR 0x40c00000
25
#define IMAGE_VIRT_ADDR 0x40000000
27
extern int initrd_can_do_64bit_phys;
29
static char *sun4u_memory_find (unsigned int len, int is_kernel);
31
struct linux_prom_registers prom_reg_memlist[64];
32
struct linux_mlist_v0 prom_phys_avail[64];
34
/* Internal Prom library routine to sort a linux_mlist_v0 memory
35
* list. Used below in initialization.
37
static void prom_sortmemlist (struct linux_mlist_v0 *thislist)
44
for (i = 0; thislist[i].theres_more != 0; i++) {
45
lowest = thislist[i].start_adr;
46
for (mitr = i + 1; thislist[mitr - 1].theres_more != 0; mitr++)
47
if (thislist[mitr].start_adr < lowest) {
48
lowest = thislist[mitr].start_adr;
51
if (lowest == thislist[i].start_adr)
53
tmpaddr = thislist[swapi].start_adr;
54
tmpsize = thislist[swapi].num_bytes;
55
for (mitr = swapi; mitr > i; mitr--) {
56
thislist[mitr].start_adr = thislist[mitr - 1].start_adr;
57
thislist[mitr].num_bytes = thislist[mitr - 1].num_bytes;
59
thislist[i].start_adr = tmpaddr;
60
thislist[i].num_bytes = tmpsize;
64
/* Initialize the memory lists based upon the prom version. */
65
struct linux_mlist_v0 *prom_meminit (void)
68
unsigned int iter, num_regs;
69
struct linux_mlist_v0 *mptr; /* ptr for traversal */
70
static int meminited = 0;
72
if (meminited) return prom_phys_avail;
77
/* Nice, kind of easier to do in this case. */
78
/* First, the total physical descriptors. */
79
/* Last, the available physical descriptors. */
80
for (mptr = (*(romvec->pv_v0mem.v0_available)), iter = 0;
81
mptr; mptr = mptr->theres_more, iter++) {
82
prom_phys_avail[iter].start_adr = mptr->start_adr;
83
prom_phys_avail[iter].num_bytes = mptr->num_bytes;
84
prom_phys_avail[iter].theres_more = &prom_phys_avail[iter + 1];
86
prom_phys_avail[iter - 1].theres_more = 0;
87
prom_sortmemlist (prom_phys_avail);
91
/* Grrr, have to traverse the prom device tree ;( */
92
node = prom_getchild (prom_root_node);
93
node = prom_searchsiblings (node, "memory");
94
num_regs = prom_getproperty (node, "available",
95
(char *) prom_reg_memlist,
96
sizeof (prom_reg_memlist));
97
num_regs = (num_regs / sizeof (struct linux_prom_registers));
98
for (iter = 0; iter < num_regs; iter++) {
99
prom_phys_avail[iter].start_adr =
100
prom_reg_memlist[iter].phys_addr;
101
prom_phys_avail[iter].num_bytes =
102
(unsigned long) prom_reg_memlist[iter].reg_size;
103
prom_phys_avail[iter].theres_more =
104
&prom_phys_avail[iter + 1];
106
prom_phys_avail[iter - 1].theres_more = 0;
107
prom_sortmemlist (prom_phys_avail);
112
return prom_phys_avail;
115
static int sun4c_hwflushes;
116
static int sun4c_linesize;
117
static void sun4c_init (void)
119
static int inited = 0;
124
propval = prom_getintdefault (prom_root_node, "vac_hwflush", -1);
125
sun4c_hwflushes = (propval == -1) ? prom_getintdefault (prom_root_node, "vac-hwflush", 0) : propval;
126
sun4c_linesize = prom_getintdefault (prom_root_node, "vac-linesize", 16);
130
void sun4c_map (unsigned long virtual, unsigned long page)
132
unsigned long virt = virtual;
135
if (sun4c_hwflushes) {
136
__asm__ __volatile__ ("\n\tsta %%g0, [%0] 0x06\n\t" : : "r" (virt));
138
unsigned long end = virt + 4096;
140
for (; virt < end; virt += sun4c_linesize)
141
__asm__ __volatile__ ("\n\tsta %%g0, [%0] 0x0d\n\t" : : "r" (virt));
144
__asm__ __volatile__ ("\n\tsta %1, [%0] 0x04\n\t" : : "r" (virt), "r" (page));
147
int sun4c_mapio (unsigned long phys, unsigned long virtual, int rdonly)
149
unsigned long page = ((phys >> 12) & 0xffff) | 0x94000000;
151
if (!rdonly) page |= 0x40000000;
152
sun4c_map (virtual & ~4095, page);
156
void sun4c_unmapio (unsigned long virtual)
158
sun4c_map (virtual & ~4095, 0);
161
inline unsigned long sun4m_get_lev1 (void)
169
"lda [%0] 32, %0\n\t"
171
"sll %0, 8, %0\n\t" : "=r" (ret));
175
inline unsigned long sun4m_probe (unsigned long l)
180
"lda [%1] 3, %0" : "=r" (ret) : "r" (l | 0x400));
184
inline unsigned long sun4m_get_direct (unsigned long l)
188
"lda [%1] 32, %0\n\t" : "=r" (ret) : "r" (l));
192
inline void sun4m_set_direct (unsigned long l, unsigned long set)
195
"sta %0, [%1] 32\n\t" : : "r" (set), "r" (l));
198
unsigned long long initrd_phys;
200
unsigned long sun4m_initrd_pa;
201
unsigned long sun4m_initrd_va;
203
char *memory_find (int len)
205
register struct linux_mlist_v0 *mlist;
206
char *beg = 0, *start;
208
unsigned long totalmem = 0;
209
char *min = (char *)0x300000;
211
if (architecture != sun4u) {
213
for (mlist = prom_phys_avail; mlist; mlist = mlist->theres_more) {
214
totalmem += mlist->num_bytes;
215
if (totalmem >= 0x4000000)
218
if (architecture != sun4c) {
220
if (totalmem >= 0x4000000)
221
min = (char *)0x3000000;
222
else if (totalmem >= 0x2000000)
223
min = (char *)0x1000000;
224
ll = (sun4m_probe (0x4000) & 0xffffff00) << 4;
228
mlist = prom_phys_avail;
230
if (beg && mlist->start_adr != beg + l)
232
start = mlist->start_adr;
233
num = mlist->num_bytes;
239
if (num + (beg ? l : 0) >= len) {
240
if (!beg) beg = start;
241
if (architecture == sun4c)
246
sun4m_initrd_pa = (unsigned long)beg;
247
initrd_phys = (unsigned long long)(unsigned long)beg;
248
lev1 = sun4m_get_lev1();
249
for (i = 0x60; i < 0xa0; i++)
250
if (!(sun4m_get_direct(lev1 + 4*i) & 3))
252
if (i == 0xa0) return (char *)0;
253
sun4m_set_direct(lev1 + 4*i, ((sun4m_initrd_pa & 0xff000000) >> 4) | 0x9e);
254
sun4m_initrd_va = i << 24;
255
return (char *)sun4m_initrd_va + (sun4m_initrd_pa & 0xffffff);
264
if (!mlist->theres_more) goto not_found;
265
mlist = mlist->theres_more;
268
return sun4u_memory_find((len + 0x1fff) & ~0x2000, 0);
274
static unsigned long long sun4u_image_virt, sun4u_image_len, sun4u_image_phys;
275
static unsigned long long sun4u_initrd_virt, sun4u_initrd_len;
276
unsigned long long sun4u_initrd_phys;
278
static char *sun4u_memory_find (unsigned int len, int is_kernel)
282
unsigned long long phys;
283
unsigned long long size;
284
} *p = (struct p1275_mem *)0;
285
unsigned int virt = (is_kernel ? IMAGE_VIRT_ADDR : INITRD_VIRT_ADDR);
286
unsigned long long phys = 0, phys_base;
288
p = (struct p1275_mem *)malloc(2048);
290
node = prom_finddevice("/memory");
292
n = prom_getproplen(node, "available");
294
if (!n || n == -1 || prom_getproperty(node, "available", (char *)p, 2048) == -1) {
296
printf("Could not get available property\n");
303
phys_base = ~(unsigned long long)0;
304
for (i = 0; i < n; i++) {
305
if (p[i].phys < phys_base)
306
phys_base = p[i].phys;
309
for (i = 0; i < n; i++) {
310
/* Do not mess with first 4 Megs of memory */
311
if (p[i].phys == phys_base) {
312
if (p[i].size <= 0x400000)
314
p[i].phys += 0x400000;
315
p[i].size -= 0x400000;
318
/* Make sure initrd doesn't overwrite kernel */
319
if (!is_kernel && p[i].phys == sun4u_image_phys) {
320
if (p[i].size <= sun4u_image_len)
322
p[i].phys += sun4u_image_len;
323
p[i].size -= sun4u_image_len;
326
/* Make sure initrd phys isn't greater than 32-bits. We
327
* can only pass unsigned int to the kernel for this
329
if (!is_kernel && !initrd_can_do_64bit_phys && p[i].phys >= 0x0000000100000000ULL)
332
if (p[i].size >= len) {
341
printf("Could not find any available memory\n");
345
if (prom_map(PROM_MAP_DEFAULT, (unsigned long long)len, virt, phys) == -1) {
346
printf("Could not map memory\n");
351
sun4u_image_len = len;
352
sun4u_image_virt = virt;
353
sun4u_image_phys = phys;
357
sun4u_initrd_len = len;
358
sun4u_initrd_virt = virt;
360
/* Not sure what the old kernel crap is for, but it
361
* expects the passed initrd physical to be relative to
362
* the phys memory base. We'll keep compatible with older
363
* kernels to avoid any problems. */
364
sun4u_initrd_phys = phys - phys_base;
370
static void sun4u_memory_release(int is_kernel)
372
unsigned long long virt, len;
375
virt = sun4u_image_virt;
376
len = sun4u_image_len;
378
virt = sun4u_initrd_virt;
379
len = sun4u_initrd_len;
386
prom_unmap(len, virt);
391
sun4u_initrd_len = 0;
394
char *image_memory_find (unsigned int len)
396
/* This only works for sparc64 */
397
if (architecture != sun4u)
400
return sun4u_memory_find(len, 1);
403
void image_memory_release(void)
405
if (architecture != sun4u)
408
sun4u_memory_release(1);
411
void memory_release(void)
413
if (architecture == sun4u) {
414
sun4u_memory_release(0);
415
} else if (sun4m_initrd_pa) {
417
lev1 = sun4m_get_lev1();
418
sun4m_set_direct(lev1 + (sun4m_initrd_va >> 24) * 4, 0);