patch-2.1.53 linux/arch/sparc64/kernel/ebus.c
Next file: linux/arch/sparc64/kernel/entry.S
Previous file: linux/arch/sparc64/kernel/central.c
Back to the patch index
Back to the overall index
- Lines: 191
- Date:
Thu Sep 4 12:54:48 1997
- Orig file:
v2.1.52/linux/arch/sparc64/kernel/ebus.c
- Orig date:
Mon Aug 18 18:19:45 1997
diff -u --recursive --new-file v2.1.52/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.2 1997/08/15 06:44:13 davem Exp $
+/* $Id: ebus.c,v 1.7 1997/08/28 02:23:17 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -6,20 +6,23 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/types.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/system.h>
+#include <asm/page.h>
#include <asm/pbm.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
#include <asm/bpp.h>
-struct linux_ebus *ebus_chain = 0;
+#undef DEBUG_FILL_EBUS_DEV
-static char lbuf[128];
+struct linux_ebus *ebus_chain = 0;
extern void prom_ebus_ranges_init(struct linux_ebus *);
+extern unsigned long pci_console_init(unsigned long memory_start);
#ifdef CONFIG_SUN_OPENPROMIO
extern int openprom_init(void);
@@ -34,57 +37,74 @@
extern void auxio_probe(void);
#endif
+extern unsigned int psycho_irq_build(unsigned int full_ino);
+
__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
{
+ struct linux_prom_registers regs[PROMREG_MAX];
int irqs[PROMINTR_MAX];
- int i, len;
+ char lbuf[128];
+ int i, n, len;
+#ifndef CONFIG_PCI
+ return;
+#endif
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
- len = prom_getproperty(node, "reg", (void *)dev->regs,
- sizeof(dev->regs));
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
(int)sizeof(struct linux_prom_registers));
panic(__FUNCTION__);
}
- dev->num_registers = len / sizeof(struct linux_prom_registers);
+ dev->num_addrs = len / sizeof(struct linux_prom_registers);
- prom_apply_ebus_ranges(dev->parent, dev->regs, dev->num_registers);
-#if 0 /* XXX No longer exists/needed in new framework... */
- prom_apply_pbm_ranges(dev->parent->parent, dev->regs,
- dev->num_registers);
-#endif
+ for (i = 0; i < dev->num_addrs; i++) {
+ n = (regs[i].which_io - 0x10) >> 2;
+
+ dev->base_address[i] = dev->parent->self->base_address[n];
+ dev->base_address[i] += (unsigned long)regs[i].phys_addr;
+ }
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
- dev->irqs[0].pri = 0;
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
for (i = 0; i < dev->num_irqs; i++)
- dev->irqs[i].pri = irqs[i];
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
}
- printk("Found '%s' at %x.%08x", dev->prom_name,
- dev->regs[0].which_io, dev->regs[0].phys_addr);
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("'%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
if (dev->num_irqs) {
- printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
for (i = 0; i < dev->num_irqs; i++)
- printk(" %03x", dev->irqs[i].pri);
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
}
- printk("\n");
+#endif
}
__initfunc(unsigned long ebus_init(unsigned long memory_start,
unsigned long memory_end))
{
+ struct linux_prom_pci_registers regs[PROMREG_MAX];
+ struct linux_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
- int nd, ebusnd, topnd;
+ struct pci_dev *pdev;
+ char lbuf[128];
+ unsigned long addr, *base;
+ int nd, len, ebusnd, topnd;
+ int reg, rng, nreg;
+ int devfn;
int num_ebus = 0;
#ifndef CONFIG_PCI
@@ -108,12 +128,55 @@
ebus->next = 0;
while (ebusnd) {
- printk("ebus%d: ", num_ebus);
+ printk("ebus%d:\n", num_ebus);
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
strcpy(ebus->prom_name, lbuf);
- ebus->parent = &psycho_root->pbm_B;
+ ebus->parent = pbm = &psycho_root->pbm_B;
+
+ len = prom_getproperty(ebusnd, "reg", (void *)regs,
+ sizeof(regs));
+ if (len == 0 || len == -1) {
+ prom_printf("%s: can't find reg property\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+ nreg = len / sizeof(struct linux_prom_pci_registers);
+
+ devfn = (regs[0].phys_hi >> 8) & 0xff;
+ for (pdev = pbm->pci_bus.devices; pdev; pdev = pdev->sibling)
+ if (pdev->devfn == devfn)
+ break;
+ if (!pdev) {
+ prom_printf("%s: can't find PCI device\n",
+ __FUNCTION__);
+ prom_halt();
+ }
+ ebus->self = pdev;
+
+ base = &ebus->self->base_address[0];
+ for (reg = 0; reg < nreg; reg++) {
+ if (!(regs[reg].phys_hi & 0x03000000))
+ continue;
+
+ for (rng = 0; rng < pbm->num_pbm_ranges; rng++) {
+ struct linux_prom_pci_ranges *rp =
+ &pbm->pbm_ranges[rng];
+
+ if ((rp->child_phys_hi ^ regs[reg].phys_hi)
+ & 0x03000000)
+ continue;
+
+ addr = (u64)regs[reg].phys_lo;
+ addr += (u64)regs[reg].phys_mid << 32UL;
+ addr += (u64)rp->parent_phys_lo;
+ addr += (u64)rp->parent_phys_hi << 32UL;
+ *base++ = (unsigned long)__va(addr);
+
+ break;
+ }
+ }
prom_ebus_ranges_init(ebus);
@@ -139,6 +202,8 @@
ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
++num_ebus;
}
+
+ memory_start = pci_console_init(memory_start);
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov