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

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