patch-2.1.54 linux/arch/sparc64/kernel/ebus.c
Next file: linux/arch/sparc64/kernel/ioctl32.c
Previous file: linux/arch/sparc64/defconfig
Back to the patch index
Back to the overall index
- Lines: 244
- Date:
Sat Sep 6 10:04:15 1997
- Orig file:
v2.1.53/linux/arch/sparc64/kernel/ebus.c
- Orig date:
Thu Sep 4 17:07:30 1997
diff -u --recursive --new-file v2.1.53/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.7 1997/08/28 02:23:17 ecd Exp $
+/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -39,16 +39,72 @@
extern unsigned int psycho_irq_build(unsigned int full_ino);
-__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+static inline unsigned long
+ebus_alloc(unsigned long *memory_start, size_t size)
+{
+ unsigned long mem;
+
+ *memory_start = (*memory_start + 7) & ~(7);
+ mem = *memory_start;
+ *memory_start += size;
+ return mem;
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
+{
+ int regs[PROMREG_MAX];
+ int irqs[PROMREG_MAX];
+ char lbuf[128];
+ int i, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ dev->num_addrs = len / sizeof(regs[0]);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ if (regs[i] >= dev->parent->num_addrs) {
+ prom_printf("UGH: property for %s was %d, need < %d\n",
+ dev->prom_name, len, dev->parent->num_addrs);
+ panic(__FUNCTION__);
+ }
+ dev->base_address[i] = dev->parent->base_address[regs[i]];
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("child '%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" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+}
+
+__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+ unsigned long memory_start))
{
struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
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);
@@ -90,6 +146,27 @@
printk("\n");
}
#endif
+ if ((node = prom_getchild(node))) {
+ dev->children = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = dev->children;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+
+ while ((node = prom_getsibling(node))) {
+ child->next = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = child->next;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+ }
+ }
+
+ return memory_start;
}
__initfunc(unsigned long ebus_init(unsigned long memory_start,
@@ -100,31 +177,32 @@
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct pci_dev *pdev;
+ struct pcidev_cookie *cookie;
char lbuf[128];
unsigned long addr, *base;
- int nd, len, ebusnd, topnd;
+ unsigned short pci_command;
+ int nd, len, ebusnd;
int reg, rng, nreg;
- int devfn;
int num_ebus = 0;
-#ifndef CONFIG_PCI
- return memory_start;
-#endif
-
- memory_start = ((memory_start + 7) & (~7));
-
- topnd = psycho_root->pbm_B.prom_node;
- if (!topnd)
+ if (!pcibios_present())
return memory_start;
- ebusnd = prom_searchsiblings(prom_getchild(topnd), "ebus");
- if (ebusnd == 0) {
- printk("EBUS: No EBUS's found.\n");
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev) {
+ printk("ebus: No EBus's found.\n");
return memory_start;
}
- ebus_chain = ebus = (struct linux_ebus *)memory_start;
- memory_start += sizeof(struct linux_ebus);
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus_chain = ebus = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
ebus->next = 0;
while (ebusnd) {
@@ -133,7 +211,16 @@
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
strcpy(ebus->prom_name, lbuf);
- ebus->parent = pbm = &psycho_root->pbm_B;
+
+ ebus->self = pdev;
+ ebus->parent = pbm = cookie->pbm;
+
+ /* Enable BUS Master. */
+ pcibios_read_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, pci_command);
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
@@ -144,17 +231,6 @@
}
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))
@@ -181,25 +257,41 @@
prom_ebus_ranges_init(ebus);
nd = prom_getchild(ebusnd);
- ebus->devices = (struct linux_ebus_device *)memory_start;
- memory_start += sizeof(struct linux_ebus_device);
+ ebus->devices = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
dev = ebus->devices;
dev->next = 0;
+ dev->children = 0;
dev->parent = ebus;
- fill_ebus_device(nd, dev);
+ memory_start = fill_ebus_device(nd, dev, memory_start);
while ((nd = prom_getsibling(nd))) {
- dev->next = (struct linux_ebus_device *)memory_start;
- memory_start += sizeof(struct linux_ebus_device);
+ dev->next = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = 0;
+ dev->children = 0;
dev->parent = ebus;
- fill_ebus_device(nd, dev);
+ memory_start = fill_ebus_device(nd, dev, memory_start);
}
- ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
+ for (pdev = pdev->next; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev)
+ break;
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus->next = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus = ebus->next;
+ ebus->next = 0;
++num_ebus;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov