X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Febus.c;h=c69504aa638f59418a3bf08040cabb57fc85767f;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=8a9b470e1b651883ca6023313295a94775d78566;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 8a9b470e1..c69504aa6 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -5,6 +5,7 @@ * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ +#include #include #include #include @@ -19,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -140,7 +139,7 @@ int ebus_dma_irq_enable(struct ebus_dma_info *p, int on) if (on) { if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) { - if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p)) + if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p)) return -EBUSY; } @@ -270,6 +269,10 @@ EXPORT_SYMBOL(ebus_dma_enable); struct linux_ebus *ebus_chain = NULL; +#ifdef CONFIG_SUN_AUXIO +extern void auxio_probe(void); +#endif + static inline void *ebus_alloc(size_t size) { void *mem; @@ -280,22 +283,77 @@ static inline void *ebus_alloc(size_t size) return mem; } -static void __init fill_ebus_child(struct device_node *dp, - struct linux_ebus_child *dev, - int non_standard_regs) +static void __init ebus_ranges_init(struct linux_ebus *ebus) +{ + int success; + + ebus->num_ebus_ranges = 0; + success = prom_getproperty(ebus->prom_node, "ranges", + (char *)ebus->ebus_ranges, + sizeof(ebus->ebus_ranges)); + if (success != -1) + ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); +} + +static void __init ebus_intmap_init(struct linux_ebus *ebus) +{ + int success; + + ebus->num_ebus_intmap = 0; + success = prom_getproperty(ebus->prom_node, "interrupt-map", + (char *)ebus->ebus_intmap, + sizeof(ebus->ebus_intmap)); + if (success == -1) + return; + + ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap)); + + success = prom_getproperty(ebus->prom_node, "interrupt-map-mask", + (char *)&ebus->ebus_intmask, + sizeof(ebus->ebus_intmask)); + if (success == -1) { + prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); + prom_halt(); + } +} + +int __init ebus_intmap_match(struct linux_ebus *ebus, + struct linux_prom_registers *reg, + int *interrupt) { - struct of_device *op; - int *regs; + unsigned int hi, lo, irq; + int i; + + if (!ebus->num_ebus_intmap) + return 0; + + hi = reg->which_io & ebus->ebus_intmask.phys_hi; + lo = reg->phys_addr & ebus->ebus_intmask.phys_lo; + irq = *interrupt & ebus->ebus_intmask.interrupt; + for (i = 0; i < ebus->num_ebus_intmap; i++) { + if ((ebus->ebus_intmap[i].phys_hi == hi) && + (ebus->ebus_intmap[i].phys_lo == lo) && + (ebus->ebus_intmap[i].interrupt == irq)) { + *interrupt = ebus->ebus_intmap[i].cinterrupt; + return 0; + } + } + return -1; +} + +void __init fill_ebus_child(int node, struct linux_prom_registers *preg, + struct linux_ebus_child *dev, int non_standard_regs) +{ + int regs[PROMREG_MAX]; + int irqs[PROMREG_MAX]; int i, len; - dev->prom_node = dp; - printk(" (%s)", dp->name); + dev->prom_node = node; + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk(" (%s)", dev->prom_name); - regs = of_get_property(dp, "reg", &len); - if (!regs) - dev->num_addrs = 0; - else - dev->num_addrs = len / sizeof(regs[0]); + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + dev->num_addrs = len / sizeof(regs[0]); if (non_standard_regs) { /* This is to handle reg properties which are not @@ -312,34 +370,30 @@ static void __init fill_ebus_child(struct device_node *dp, int rnum = regs[i]; if (rnum >= dev->parent->num_addrs) { prom_printf("UGH: property for %s was %d, need < %d\n", - dp->name, len, dev->parent->num_addrs); - prom_halt(); + dev->prom_name, len, dev->parent->num_addrs); + panic(__FUNCTION__); } dev->resource[i].start = dev->parent->resource[i].start; dev->resource[i].end = dev->parent->resource[i].end; dev->resource[i].flags = IORESOURCE_MEM; - dev->resource[i].name = dp->name; + dev->resource[i].name = dev->prom_name; } } - op = of_find_device_by_node(dp); - if (!op) { - dev->num_irqs = 0; - } else { - dev->num_irqs = op->num_irqs; - for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = op->irqs[i]; - } + for (i = 0; i < PROMINTR_MAX; i++) + dev->irqs[i] = PCI_IRQ_NONE; - if (!dev->num_irqs) { + len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); + if ((len == -1) || (len == 0)) { + dev->num_irqs = 0; /* * Oh, well, some PROMs don't export interrupts * property to children of EBus devices... * * Be smart about PS/2 keyboard and mouse. */ - if (!strcmp(dev->parent->prom_node->name, "8042")) { - if (!strcmp(dev->prom_node->name, "kb_ps2")) { + if (!strcmp(dev->parent->prom_name, "8042")) { + if (!strcmp(dev->prom_name, "kb_ps2")) { dev->num_irqs = 1; dev->irqs[0] = dev->parent->irqs[0]; } else { @@ -347,57 +401,103 @@ static void __init fill_ebus_child(struct device_node *dp, dev->irqs[0] = dev->parent->irqs[1]; } } + } else { + dev->num_irqs = len / sizeof(irqs[0]); + for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + + if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(pbm, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } + } } } static int __init child_regs_nonstandard(struct linux_ebus_device *dev) { - if (!strcmp(dev->prom_node->name, "i2c") || - !strcmp(dev->prom_node->name, "SUNW,lombus")) + if (!strcmp(dev->prom_name, "i2c") || + !strcmp(dev->prom_name, "SUNW,lombus")) return 1; return 0; } -static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev) +void __init fill_ebus_device(int node, struct linux_ebus_device *dev) { + struct linux_prom_registers regs[PROMREG_MAX]; struct linux_ebus_child *child; - struct of_device *op; - int i, len; + int irqs[PROMINTR_MAX]; + int i, n, len; - dev->prom_node = dp; + dev->prom_node = node; + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk(" [%s", dev->prom_name); - printk(" [%s", dp->name); - - op = of_find_device_by_node(dp); - if (!op) { + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + if (len == -1) { dev->num_addrs = 0; - dev->num_irqs = 0; - } else { - (void) of_get_property(dp, "reg", &len); - dev->num_addrs = len / sizeof(struct linux_prom_registers); - - for (i = 0; i < dev->num_addrs; i++) - memcpy(&dev->resource[i], - &op->resource[i], - sizeof(struct resource)); + goto probe_interrupts; + } - dev->num_irqs = op->num_irqs; - for (i = 0; i < dev->num_irqs; i++) - dev->irqs[i] = op->irqs[i]; + 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)); + prom_halt(); + } + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) { + /* XXX Learn how to interpret ebus ranges... -DaveM */ + if (regs[i].which_io >= 0x10) + n = (regs[i].which_io - 0x10) >> 2; + else + n = regs[i].which_io; + + dev->resource[i].start = dev->bus->self->resource[n].start; + dev->resource[i].start += (unsigned long)regs[i].phys_addr; + dev->resource[i].end = + (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; + request_resource(&dev->bus->self->resource[n], + &dev->resource[i]); } - dev->ofdev.node = dp; - dev->ofdev.dev.parent = &dev->bus->ofdev.dev; - dev->ofdev.dev.bus = &ebus_bus_type; - strcpy(dev->ofdev.dev.bus_id, dp->path_component_name); +probe_interrupts: + for (i = 0; i < PROMINTR_MAX; i++) + dev->irqs[i] = PCI_IRQ_NONE; - /* Register with core */ - if (of_device_register(&dev->ofdev) != 0) - printk(KERN_DEBUG "ebus: device registration error for %s!\n", - dev->ofdev.dev.bus_id); + 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++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + + if (ebus_intmap_match(dev->bus, ®s[0], &irqs[i]) != -1) { + dev->irqs[i] = p->irq_build(pbm, + dev->bus->self, + irqs[i]); + } else { + /* If we get a bogus interrupt property, just + * record the raw value instead of punting. + */ + dev->irqs[i] = irqs[i]; + } + } + } - dp = dp->child; - if (dp) { + if ((node = prom_getchild(node))) { printk(" ->"); dev->children = ebus_alloc(sizeof(struct linux_ebus_child)); @@ -405,18 +505,18 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, child, - child_regs_nonstandard(dev)); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); - while ((dp = dp->sibling) != NULL) { + while ((node = prom_getsibling(node)) != 0) { child->next = ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; child->next = NULL; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(dp, child, - child_regs_nonstandard(dev)); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); } } printk("]"); @@ -443,8 +543,7 @@ void __init ebus_init(void) struct linux_ebus *ebus; struct pci_dev *pdev; struct pcidev_cookie *cookie; - struct device_node *dp; - int is_rio; + int nd, ebusnd, is_rio; int num_ebus = 0; pdev = find_next_ebus(NULL, &is_rio); @@ -454,22 +553,20 @@ void __init ebus_init(void) } cookie = pdev->sysdata; - dp = cookie->prom_node; + ebusnd = cookie->prom_node; ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = NULL; ebus->is_rio = is_rio; - while (dp) { - struct device_node *child; - + while (ebusnd) { /* SUNW,pci-qfe uses four empty ebuses on it. I think we should not consider them here, as they have half of the properties this code expects and once we do PCI hot-plug, we'd have to tweak with the ebus_chain in the runtime after initialization. -jj */ - if (!dp->child) { + if (!prom_getchild (ebusnd)) { pdev = find_next_ebus(pdev, &is_rio); if (!pdev) { if (ebus == ebus_chain) { @@ -481,29 +578,22 @@ void __init ebus_init(void) } ebus->is_rio = is_rio; cookie = pdev->sysdata; - dp = cookie->prom_node; + ebusnd = cookie->prom_node; continue; } printk("ebus%d:", num_ebus); + prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name)); ebus->index = num_ebus; - ebus->prom_node = dp; + ebus->prom_node = ebusnd; ebus->self = pdev; ebus->parent = pbm = cookie->pbm; - ebus->ofdev.node = dp; - ebus->ofdev.dev.parent = &pdev->dev; - ebus->ofdev.dev.bus = &ebus_bus_type; - strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name); - - /* Register with core */ - if (of_device_register(&ebus->ofdev) != 0) - printk(KERN_DEBUG "ebus: device registration error for %s!\n", - ebus->ofdev.dev.bus_id); + ebus_ranges_init(ebus); + ebus_intmap_init(ebus); - - child = dp->child; - if (!child) + nd = prom_getchild(ebusnd); + if (!nd) goto next_ebus; ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); @@ -512,16 +602,16 @@ void __init ebus_init(void) dev->next = NULL; dev->children = NULL; dev->bus = ebus; - fill_ebus_device(child, dev); + fill_ebus_device(nd, dev); - while ((child = child->sibling) != NULL) { + while ((nd = prom_getsibling(nd)) != 0) { dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; dev->next = NULL; dev->children = NULL; dev->bus = ebus; - fill_ebus_device(child, dev); + fill_ebus_device(nd, dev); } next_ebus: @@ -532,7 +622,7 @@ void __init ebus_init(void) break; cookie = pdev->sysdata; - dp = cookie->prom_node; + ebusnd = cookie->prom_node; ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; @@ -541,4 +631,8 @@ void __init ebus_init(void) ++num_ebus; } pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */ + +#ifdef CONFIG_SUN_AUXIO + auxio_probe(); +#endif }