patch-2.1.97 linux/arch/ppc/kernel/prom.c
Next file: linux/arch/ppc/kernel/ptrace.c
Previous file: linux/arch/ppc/kernel/process.c
Back to the patch index
Back to the overall index
- Lines: 492
- Date:
Tue Apr 14 17:33:58 1998
- Orig file:
v2.1.96/linux/arch/ppc/kernel/prom.c
- Orig date:
Mon Jan 12 15:18:13 1998
diff -u --recursive --new-file v2.1.96/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
@@ -16,6 +16,8 @@
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
/*
* Properties whose value is longer than this get excluded from our
@@ -50,6 +52,19 @@
unsigned size_lo;
};
+struct isa_reg_property {
+ unsigned space;
+ unsigned address;
+ unsigned size;
+};
+
+typedef unsigned long interpret_func(struct device_node *, unsigned long);
+static interpret_func interpret_pci_props;
+static interpret_func interpret_dbdma_props;
+static interpret_func interpret_isa_props;
+static interpret_func interpret_macio_props;
+static interpret_func interpret_root_props;
+
char *prom_display_paths[FB_MAX] __initdata = { 0, };
unsigned int prom_num_displays = 0;
@@ -60,19 +75,21 @@
char *bootpath = 0;
char *bootdevice = 0;
-unsigned int rtas_data = 0;
-unsigned int rtas_entry = 0;
+unsigned int rtas_data = 0; /* virtual pointer */
+unsigned int rtas_entry = 0; /* physical pointer */
+unsigned int rtas_size = 0;
+char chunk[PAGE_SIZE*64];
static struct device_node *allnodes = 0;
static void *call_prom(const char *service, int nargs, int nret, ...);
-static void prom_print(const char *msg);
+ void prom_print(const char *msg);
static void prom_exit(void);
static unsigned long copy_device_tree(unsigned long, unsigned long);
static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
unsigned long, struct device_node ***);
static unsigned long finish_node(struct device_node *, unsigned long,
- unsigned long);
+ interpret_func *);
static unsigned long check_display(unsigned long);
static int prom_next_node(phandle *);
@@ -119,6 +136,18 @@
;
}
+void
+prom_enter(void)
+{
+ struct prom_args args;
+ unsigned long offset = reloc_offset();
+
+ args.service = RELOC("enter");
+ args.nargs = 0;
+ args.nret = 0;
+ RELOC(prom)(&args);
+}
+
static void *
call_prom(const char *service, int nargs, int nret, ...)
{
@@ -140,7 +169,7 @@
return prom_args.args[nargs];
}
-static void
+void
prom_print(const char *msg)
{
const char *p, *q;
@@ -160,6 +189,11 @@
}
}
+
+#ifdef CONFIG_ALL_PPC
+unsigned char OF_type[16], OF_model[16];
+#endif
+
/*
* We enter here early on, when the Open Firmware prom is still
* handling exceptions and the MMU hash table for us.
@@ -169,11 +203,14 @@
{
unsigned long mem;
ihandle prom_rtas;
- unsigned int rtas_size;
unsigned long offset = reloc_offset();
int l;
char *p, *d;
+ /* check if we're prep, return if we are */
+ if ( *(unsigned long *)(0) == 0xdeadc0de )
+ return;
+
/* First get a handle for the stdout device */
RELOC(prom) = pp;
RELOC(prom_chosen) = call_prom(RELOC("finddevice"), 1, 1,
@@ -209,27 +246,57 @@
prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas"));
if (prom_rtas != (void *) -1) {
- rtas_size = 0;
+ RELOC(rtas_size) = 0;
call_prom(RELOC("getprop"), 4, 1, prom_rtas,
- RELOC("rtas-size"), &rtas_size, sizeof(rtas_size));
+ RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size));
prom_print(RELOC("instantiating rtas..."));
- if (rtas_size == 0) {
+ if (RELOC(rtas_size) == 0) {
RELOC(rtas_data) = 0;
} else {
mem = (mem + 4095) & -4096; /* round to page bdry */
RELOC(rtas_data) = mem - KERNELBASE;
- mem += rtas_size;
+ mem += RELOC(rtas_size);
+ }
+ prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas"));
+ RELOC(rtas_data) = ((ulong)chunk+4095)&-4096;
+ {
+ int i, nargs;
+ struct prom_args prom_args;
+ nargs = 3;
+ prom_args.service = RELOC("call-method");
+ prom_args.nargs = nargs;
+ prom_args.nret = 2;
+ prom_args.args[0] = RELOC("instantiate-rtas");
+ prom_args.args[1] = prom_rtas;
+ prom_args.args[2] = ((void *)RELOC(rtas_data)-KERNELBASE);
+ RELOC(prom)(&prom_args);
+ if (prom_args.args[nargs] != 0)
+ i = 0;
+ else
+ i = (int)prom_args.args[nargs+1];
+ RELOC(rtas_entry) = i;
}
- RELOC(rtas_entry) = (unsigned int)
- call_prom(RELOC("instantiate-rtas"), 1, 1,
- RELOC(rtas_data));
- if (RELOC(rtas_entry) == -1)
+ if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0))
prom_print(RELOC(" failed\n"));
else
prom_print(RELOC(" done\n"));
}
RELOC(klimit) = (char *) (mem - offset);
+#ifdef CONFIG_ALL_PPC
+ {
+
+ ihandle prom_root;
+
+ RELOC(prom_root) = call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+ call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+ RELOC("device_type"), RELOC(OF_type),
+ (void *) 16);
+ call_prom(RELOC("getprop"), 4, 1, RELOC(prom_root),
+ RELOC("model"), RELOC(OF_model),
+ (void *) 16);
+ }
+#endif
}
/*
@@ -397,12 +464,18 @@
return mem_start;
}
+/*
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in the name, type,
+ * {n_}addrs and {n_}intrs fields of each node.
+ */
void
finish_device_tree(void)
{
unsigned long mem = (unsigned long) klimit;
- mem = finish_node(allnodes, mem, 0UL);
+ mem = finish_node(allnodes, mem, NULL);
printk(KERN_INFO "device tree used %lu bytes\n",
mem - (unsigned long) allnodes);
klimit = (char *) mem;
@@ -410,23 +483,53 @@
static unsigned long
finish_node(struct device_node *np, unsigned long mem_start,
- unsigned long base_address)
+ interpret_func *ifunc)
{
- struct reg_property *rp;
- struct pci_reg_property *pci_addrs;
- struct address_range *adr;
struct device_node *child;
- int i, l;
np->name = get_property(np, "name", 0);
np->type = get_property(np, "device_type", 0);
- /* get all the device addresses and interrupts */
- adr = (struct address_range *) mem_start;
+ /* get the device addresses and interrupts */
+ if (ifunc != NULL)
+ mem_start = ifunc(np, mem_start);
+
+ if (!strcmp(np->name, "device-tree"))
+ ifunc = interpret_root_props;
+ else if (np->type == 0)
+ ifunc = NULL;
+ else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+ ifunc = interpret_pci_props;
+ else if (!strcmp(np->type, "dbdma")
+ || (ifunc == interpret_dbdma_props
+ && (!strcmp(np->type, "escc")
+ || !strcmp(np->type, "media-bay"))))
+ ifunc = interpret_dbdma_props;
+ else if (!strcmp(np->type, "mac-io"))
+ ifunc = interpret_macio_props;
+ else if (!strcmp(np->type, "isa"))
+ ifunc = interpret_isa_props;
+ else
+ ifunc = NULL;
+
+ for (child = np->child; child != NULL; child = child->sibling)
+ mem_start = finish_node(child, mem_start, ifunc);
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_pci_props(struct device_node *np, unsigned long mem_start)
+{
+ struct address_range *adr;
+ struct pci_reg_property *pci_addrs;
+ int i, l, *ip;
+
pci_addrs = (struct pci_reg_property *)
get_property(np, "assigned-addresses", &l);
- i = 0;
- if (pci_addrs != 0) {
+ if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
while ((l -= sizeof(struct pci_reg_property)) >= 0) {
/* XXX assumes PCI addresses mapped 1-1 to physical */
adr[i].space = pci_addrs[i].addr.a_hi;
@@ -434,36 +537,194 @@
adr[i].size = pci_addrs[i].size_lo;
++i;
}
- } else {
- rp = (struct reg_property *) get_property(np, "reg", &l);
- if (rp != 0) {
- while ((l -= sizeof(struct reg_property)) >= 0) {
- adr[i].space = 0;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- ++i;
- }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_dbdma_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ unsigned long base_address;
+ int i, l, *ip;
+ struct device_node *db;
+
+ base_address = 0;
+ for (db = np->parent; db != NULL; db = db->parent) {
+ if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+ base_address = db->addrs[0].address;
+ break;
}
}
- if (i > 0) {
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address + base_address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
np->addrs = adr;
np->n_addrs = i;
mem_start += i * sizeof(struct address_range);
}
- np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
- if (np->intrs == 0)
- np->intrs = (int *) get_property(np, "interrupts", &l);
- if (np->intrs != 0)
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
- if (np->type != 0 && np->n_addrs > 0
- && (strcmp(np->type, "dbdma") == 0
- || strcmp(np->type, "mac-io") == 0))
- base_address = np->addrs[0].address;
+ return mem_start;
+}
- for (child = np->child; child != NULL; child = child->sibling)
- mem_start = finish_node(child, mem_start, base_address);
+static unsigned long
+interpret_macio_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ unsigned long base_address;
+ int i, l, *ip;
+ struct device_node *db;
+
+ base_address = 0;
+ for (db = np->parent; db != NULL; db = db->parent) {
+ if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+ base_address = db->addrs[0].address;
+ break;
+ }
+ }
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address + base_address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / (2 * sizeof(int));
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = openpic_to_irq(*ip++);
+ np->intrs[i].sense = *ip++;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_isa_props(struct device_node *np, unsigned long mem_start)
+{
+ struct isa_reg_property *rp;
+ struct address_range *adr;
+ int i, l, *ip;
+
+ rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = rp[i].space;
+ adr[i].address = rp[i].address
+ + (adr[i].space? 0: _ISA_MEM_BASE);
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / (2 * sizeof(int));
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = *ip++;
+ }
+ }
+
+ return mem_start;
+}
+
+static unsigned long
+interpret_root_props(struct device_node *np, unsigned long mem_start)
+{
+ struct reg_property *rp;
+ struct address_range *adr;
+ int i, l, *ip;
+
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0 && l >= sizeof(struct reg_property)) {
+ i = 0;
+ adr = (struct address_range *) mem_start;
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ adr[i].space = 0;
+ adr[i].address = rp[i].address;
+ adr[i].size = rp[i].size;
+ ++i;
+ }
+ np->addrs = adr;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct address_range);
+ }
+
+ ip = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (ip == 0)
+ ip = (int *) get_property(np, "interrupts", &l);
+ if (ip != 0) {
+ np->intrs = (struct interrupt_info *) mem_start;
+ np->n_intrs = l / sizeof(int);
+ mem_start += np->n_intrs * sizeof(struct interrupt_info);
+ for (i = 0; i < np->n_intrs; ++i) {
+ np->intrs[i].line = *ip++;
+ np->intrs[i].sense = 0;
+ }
+ }
return mem_start;
}
@@ -648,14 +909,14 @@
printk(KERN_ERR "No RTAS service called %s\n", service);
return -1;
}
- u.words[0] = *tokp;
+ u.words[0] = __pa(*tokp);
u.words[1] = nargs;
u.words[2] = nret;
va_start(list, outputs);
for (i = 0; i < nargs; ++i)
u.words[i+3] = va_arg(list, unsigned long);
va_end(list);
- enter_rtas(&u);
+ enter_rtas((void *)__pa(&u));
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret-1; ++i)
outputs[i] = u.words[i+nargs+4];
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov