From 8f96cd1a69d4c43e3473406a1fdf15cd9f1de5e5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 29 Jun 2006 15:08:02 -0700 Subject: [PATCH] [SPARC]: sparc32 side of of_device layer IRQ resolution. Happily, life is much simpler on 32-bit sparc systems. The "intr" property, preferred over the "interrupts" property is used-as. Some minor translations of this value happen on sun4d systems. The stage is now set to rewrite the sparc serial driver probing to use the of_driver framework, and then to convert all SBUS, EBUS, and ISA drivers in-kind so that we can nuke all those special bus frameworks. Signed-off-by: David S. Miller --- arch/sparc/kernel/of_device.c | 69 +++++++++++++++++++++++++++++++---- include/asm-sparc/of_device.h | 5 ++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index 3ebe6cc71e..bc956c5303 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c @@ -129,6 +129,26 @@ static int of_device_resume(struct device * dev) return error; } +static int node_match(struct device *dev, void *data) +{ + struct of_device *op = to_of_device(dev); + struct device_node *dp = data; + + return (op->node == dp); +} + +struct of_device *of_find_device_by_node(struct device_node *dp) +{ + struct device *dev = bus_find_device(&of_bus_type, NULL, + dp, node_match); + + if (dev) + return to_of_device(dev); + + return NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + #ifdef CONFIG_PCI struct bus_type ebus_bus_type = { .name = "ebus", @@ -503,8 +523,8 @@ static struct of_device * __init scan_one_device(struct device_node *dp, struct device *parent) { struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL); - unsigned int *irq; - int len; + struct linux_prom_irqs *intr; + int len, i; if (!op) return NULL; @@ -517,11 +537,46 @@ static struct of_device * __init scan_one_device(struct device_node *dp, if (op->portid == -1) op->portid = of_getintprop_default(dp, "portid", -1); - irq = of_get_property(dp, "interrupts", &len); - if (irq) - op->irq = *irq; - else - op->irq = 0xffffffff; + intr = of_get_property(dp, "intr", &len); + if (intr) { + op->num_irqs = len / sizeof(struct linux_prom_irqs); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = intr[i].pri; + } else { + unsigned int *irq = of_get_property(dp, "interrupts", &len); + + if (irq) { + op->num_irqs = len / sizeof(unsigned int); + for (i = 0; i < op->num_irqs; i++) + op->irqs[i] = irq[i]; + } else { + op->num_irqs = 0; + } + } + if (sparc_cpu_model == sun4d) { + static int pil_to_sbus[] = { + 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0, + }; + struct device_node *busp = dp->parent; + struct linux_prom_registers *regs; + int board = of_getintprop_default(busp, "board#", 0); + int slot; + + regs = of_get_property(dp, "reg", NULL); + slot = regs->which_io; + + for (i = 0; i < op->num_irqs; i++) { + int this_irq = op->irqs[i]; + int sbusl = pil_to_sbus[this_irq]; + + if (sbusl) + this_irq = (((board + 1) << 5) + + (sbusl << 2) + + slot); + + op->irqs[i] = this_irq; + } + } build_device_resources(op, parent); diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h index b5ca3145d4..80ea31f6e1 100644 --- a/include/asm-sparc/of_device.h +++ b/include/asm-sparc/of_device.h @@ -21,7 +21,8 @@ struct of_device struct device_node *node; struct device dev; struct resource resource[PROMREG_MAX]; - unsigned int irq; + unsigned int irqs[PROMINTR_MAX]; + int num_irqs; void *sysdata; @@ -34,6 +35,8 @@ struct of_device extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name); extern void of_iounmap(void __iomem *base, unsigned long size); +extern struct of_device *of_find_device_by_node(struct device_node *); + extern const struct of_device_id *of_match_device( const struct of_device_id *matches, const struct of_device *dev); -- 2.39.5