Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 31307
b: refs/heads/master
c: 2b1e597
h: refs/heads/master
i:
  31305: 953fb0f
  31303: 515dc27
v: v3
  • Loading branch information
David S. Miller authored and David S. Miller committed Jun 29, 2006
1 parent cb56355 commit d37cc4f
Show file tree
Hide file tree
Showing 14 changed files with 1,106 additions and 1,051 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c3a8b85f5ac2c21f4ef75e87bfe55ee7a753ffcf
refs/heads/master: 2b1e59787198e75fb2ffb3bb4fb247da1c55ac12
150 changes: 33 additions & 117 deletions trunk/arch/sparc64/kernel/ebus.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include <asm/pbm.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>

Expand Down Expand Up @@ -279,45 +281,12 @@ static inline void *ebus_alloc(size_t size)
return mem;
}

int __init ebus_intmap_match(struct linux_ebus *ebus,
struct linux_prom_registers *reg,
int *interrupt)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmask *imask;
unsigned int hi, lo, irq;
int i, len, n_imap;

imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);

imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;

hi = reg->which_io & imask->phys_hi;
lo = reg->phys_addr & imask->phys_lo;
irq = *interrupt & imask->interrupt;
for (i = 0; i < n_imap; i++) {
if ((imap[i].phys_hi == hi) &&
(imap[i].phys_lo == lo) &&
(imap[i].interrupt == irq)) {
*interrupt = imap[i].cinterrupt;
return 0;
}
}
return -1;
}

void __init fill_ebus_child(struct device_node *dp,
struct linux_prom_registers *preg,
struct linux_ebus_child *dev,
int non_standard_regs)
static void __init fill_ebus_child(struct device_node *dp,
struct linux_ebus_child *dev,
int non_standard_regs)
{
struct of_device *op;
int *regs;
int *irqs;
int i, len;

dev->prom_node = dp;
Expand Down Expand Up @@ -354,12 +323,16 @@ void __init fill_ebus_child(struct device_node *dp,
}
}

for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;

irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
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];
}

if (!dev->num_irqs) {
/*
* Oh, well, some PROMs don't export interrupts
* property to children of EBus devices...
Expand All @@ -375,23 +348,6 @@ 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];
}
}
}
}

Expand All @@ -403,72 +359,32 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
return 0;
}

void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_prom_registers *regs;
struct linux_ebus_child *child;
int *irqs;
int i, n, len;
struct of_device *op;
int i, len;

dev->prom_node = dp;

printk(" [%s", dp->name);

regs = of_get_property(dp, "reg", &len);
if (!regs) {
op = of_find_device_by_node(dp);
if (!op) {
dev->num_addrs = 0;
goto probe_interrupts;
}

if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_node->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_node->name;
request_resource(&dev->bus->self->resource[n],
&dev->resource[i]);
}

probe_interrupts:
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;

irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
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, &regs[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];
}
}
(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));

dev->num_irqs = op->num_irqs;
for (i = 0; i < dev->num_irqs; i++)
dev->irqs[i] = op->irqs[i];
}

dev->ofdev.node = dp;
Expand All @@ -490,7 +406,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(dp, regs, child,
fill_ebus_child(dp, child,
child_regs_nonstandard(dev));

while ((dp = dp->sibling) != NULL) {
Expand All @@ -500,7 +416,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(dp, regs, child,
fill_ebus_child(dp, child,
child_regs_nonstandard(dev));
}
}
Expand Down
101 changes: 6 additions & 95 deletions trunk/arch/sparc64/kernel/isa.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/isa.h>

struct sparc_isa_bridge *isa_chain;
Expand Down Expand Up @@ -46,107 +48,16 @@ isa_dev_get_resource(struct sparc_isa_device *isa_dev)
return pregs;
}

/* I can't believe they didn't put a real INO in the isa device
* interrupts property. The whole point of the OBP properties
* is to shield the kernel from IRQ routing details.
*
* The P1275 standard for ISA devices seems to also have been
* totally ignored.
*
* On later systems, an interrupt-map and interrupt-map-mask scheme
* akin to EBUS is used.
*/
static struct {
int obp_irq;
int pci_ino;
} grover_irq_table[] = {
{ 1, 0x00 }, /* dma, unknown ino at this point */
{ 2, 0x27 }, /* floppy */
{ 3, 0x22 }, /* parallel */
{ 4, 0x2b }, /* serial */
{ 5, 0x25 }, /* acpi power management */

{ 0, 0x00 } /* end of table */
};

static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
struct sparc_isa_bridge *isa_br,
int *interrupt,
struct linux_prom_registers *reg)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmask *imask;
unsigned int hi, lo, irq;
int i, len, n_imap;

imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);

imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;

hi = reg->which_io & imask->phys_hi;
lo = reg->phys_addr & imask->phys_lo;
irq = *interrupt & imask->interrupt;
for (i = 0; i < n_imap; i++) {
if ((imap[i].phys_hi == hi) &&
(imap[i].phys_lo == lo) &&
(imap[i].interrupt == irq)) {
*interrupt = imap[i].cinterrupt;
return 0;
}
}
return -1;
}

static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
struct linux_prom_registers *pregs)
{
int irq_prop;
struct of_device *op = of_find_device_by_node(isa_dev->prom_node);

irq_prop = of_getintprop_default(isa_dev->prom_node,
"interrupts", -1);
if (irq_prop <= 0) {
goto no_irq;
if (!op || !op->num_irqs) {
isa_dev->irq = PCI_IRQ_NONE;
} else {
struct pci_controller_info *pcic;
struct pci_pbm_info *pbm;
int i;

if (of_find_property(isa_dev->bus->prom_node,
"interrupt-map", NULL)) {
if (!isa_dev_get_irq_using_imap(isa_dev,
isa_dev->bus,
&irq_prop,
pregs))
goto route_irq;
}

for (i = 0; grover_irq_table[i].obp_irq != 0; i++) {
if (grover_irq_table[i].obp_irq == irq_prop) {
int ino = grover_irq_table[i].pci_ino;

if (ino == 0)
goto no_irq;

irq_prop = ino;
goto route_irq;
}
}
goto no_irq;

route_irq:
pbm = isa_dev->bus->parent;
pcic = pbm->parent;
isa_dev->irq = pcic->irq_build(pbm, NULL, irq_prop);
return;
isa_dev->irq = op->irqs[0];
}

no_irq:
isa_dev->irq = PCI_IRQ_NONE;
}

static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
Expand Down
Loading

0 comments on commit d37cc4f

Please sign in to comment.