Commit a23414be authored by Paul Mackerras's avatar Paul Mackerras

ppc/powerpc: workarounds for old Open Firmware versions

This adds code to work around some problems with old versions of
Open Firmware, such as on the early powermacs (7500 etc.) and the
"Longtrail" CHRP machine.  On these machines we have to claim
the physical and virtual address ranges explicitly when claiming
memory and then set up a V->P mapping.

The Longtrail has more problems: setprop doesn't work, and we have
to set an "allow-reclaim" variable to 0 in order to get claim on
physical memory ranges to fail if the memory is already claimed.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 8b553f32
...@@ -1264,7 +1264,14 @@ static int __init early_init_dt_scan_memory(unsigned long node, ...@@ -1264,7 +1264,14 @@ static int __init early_init_dt_scan_memory(unsigned long node,
unsigned long l; unsigned long l;
/* We are scanning "memory" nodes only */ /* We are scanning "memory" nodes only */
if (type == NULL || strcmp(type, "memory") != 0) if (type == NULL) {
/*
* The longtrail doesn't have a device_type on the
* /memory node, so look for the node called /memory@0.
*/
if (depth != 1 || strcmp(uname, "memory@0") != 0)
return 0;
} else if (strcmp(type, "memory") != 0)
return 0; return 0;
reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
......
This diff is collapsed.
...@@ -361,7 +361,9 @@ static void __init chrp_find_openpic(void) ...@@ -361,7 +361,9 @@ static void __init chrp_find_openpic(void)
printk(KERN_INFO "OpenPIC at %lx\n", opaddr); printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */ irq_count = NR_IRQS - NUM_ISA_INTERRUPTS - 4; /* leave room for IPIs */
prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS - 4); prom_get_irq_senses(init_senses, NUM_ISA_INTERRUPTS, NR_IRQS - 4);
/* i8259 cascade is always positive level */
init_senses[0] = IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE;
iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len);
if (iranges == NULL) if (iranges == NULL)
......
...@@ -19,6 +19,9 @@ extern prom_entry of_prom_entry; ...@@ -19,6 +19,9 @@ extern prom_entry of_prom_entry;
/* function declarations */ /* function declarations */
int call_prom(const char *service, int nargs, int nret, ...);
int call_prom_ret(const char *service, int nargs, int nret,
unsigned int *rets, ...);
void * claim(unsigned int virt, unsigned int size, unsigned int align); void * claim(unsigned int virt, unsigned int size, unsigned int align);
int map(unsigned int phys, unsigned int virt, unsigned int size); int map(unsigned int phys, unsigned int virt, unsigned int size);
void enter(void); void enter(void);
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
# #
lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \
ofstdio.o read.o release.o write.o map.o ofstdio.o read.o release.o write.o map.o call_prom.o
/*
* Copyright (C) 1996-2005 Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include "of1275.h"
#include <stdarg.h>
int call_prom(const char *service, int nargs, int nret, ...)
{
int i;
struct prom_args {
const char *service;
int nargs;
int nret;
unsigned int args[12];
} args;
va_list list;
args.service = service;
args.nargs = nargs;
args.nret = nret;
va_start(list, nret);
for (i = 0; i < nargs; i++)
args.args[i] = va_arg(list, unsigned int);
va_end(list);
for (i = 0; i < nret; i++)
args.args[nargs+i] = 0;
if (of_prom_entry(&args) < 0)
return -1;
return (nret > 0)? args.args[nargs]: 0;
}
int call_prom_ret(const char *service, int nargs, int nret,
unsigned int *rets, ...)
{
int i;
struct prom_args {
const char *service;
int nargs;
int nret;
unsigned int args[12];
} args;
va_list list;
args.service = service;
args.nargs = nargs;
args.nret = nret;
va_start(list, rets);
for (i = 0; i < nargs; i++)
args.args[i] = va_arg(list, unsigned int);
va_end(list);
for (i = 0; i < nret; i++)
args.args[nargs+i] = 0;
if (of_prom_entry(&args) < 0)
return -1;
if (rets != (void *) 0)
for (i = 1; i < nret; ++i)
rets[i-1] = args.args[nargs+i];
return (nret > 0)? args.args[nargs]: 0;
}
...@@ -9,27 +9,84 @@ ...@@ -9,27 +9,84 @@
*/ */
#include "of1275.h" #include "of1275.h"
#include "nonstdio.h"
void * /*
claim(unsigned int virt, unsigned int size, unsigned int align) * Older OF's require that when claiming a specific range of addresses,
* we claim the physical space in the /memory node and the virtual
* space in the chosen mmu node, and then do a map operation to
* map virtual to physical.
*/
static int need_map = -1;
static ihandle chosen_mmu;
static phandle memory;
/* returns true if s2 is a prefix of s1 */
static int string_match(const char *s1, const char *s2)
{
for (; *s2; ++s2)
if (*s1++ != *s2)
return 0;
return 1;
}
static int check_of_version(void)
{ {
struct prom_args { phandle oprom, chosen;
char *service; char version[64];
int nargs;
int nret; oprom = finddevice("/openprom");
unsigned int virt; if (oprom == OF_INVALID_HANDLE)
unsigned int size; return 0;
unsigned int align; if (getprop(oprom, "model", version, sizeof(version)) <= 0)
void *ret; return 0;
} args; version[sizeof(version)-1] = 0;
printf("OF version = '%s'\n", version);
args.service = "claim"; if (!string_match(version, "Open Firmware, 1.")
args.nargs = 3; && !string_match(version, "FirmWorks,3."))
args.nret = 1; return 0;
args.virt = virt; chosen = finddevice("/chosen");
args.size = size; if (chosen == OF_INVALID_HANDLE) {
args.align = align; chosen = finddevice("/chosen@0");
args.ret = (void *) 0; if (chosen == OF_INVALID_HANDLE) {
(*of_prom_entry)(&args); printf("no chosen\n");
return args.ret; return 0;
}
}
if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
printf("no mmu\n");
return 0;
}
memory = (ihandle) call_prom("open", 1, 1, "/memory");
if (memory == OF_INVALID_HANDLE) {
memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
if (memory == OF_INVALID_HANDLE) {
printf("no memory node\n");
return 0;
}
}
printf("old OF detected\n");
return 1;
}
void *claim(unsigned int virt, unsigned int size, unsigned int align)
{
int ret;
unsigned int result;
if (need_map < 0)
need_map = check_of_version();
if (align || !need_map)
return (void *) call_prom("claim", 3, 1, virt, size, align);
ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
align, size, virt);
if (ret != 0 || result == -1)
return (void *) -1;
ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
align, size, virt);
/* 0x12 == coherent + read/write */
ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
0x12, size, virt, virt);
return virt;
} }
...@@ -10,22 +10,7 @@ ...@@ -10,22 +10,7 @@
#include "of1275.h" #include "of1275.h"
phandle phandle finddevice(const char *name)
finddevice(const char *name)
{ {
struct prom_args { return (phandle) call_prom("finddevice", 1, 1, name);
char *service;
int nargs;
int nret;
const char *devspec;
phandle device;
} args;
args.service = "finddevice";
args.nargs = 1;
args.nret = 1;
args.devspec = name;
args.device = OF_INVALID_HANDLE;
(*of_prom_entry)(&args);
return args.device;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment