diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-07-12 21:16:07 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-07-13 01:50:13 -0700 |
commit | 9bbd952e7f965757b5c913b6f98ad37a191137bd (patch) | |
tree | 134f38166dd1829c14739fcecd453f0bf2c1136d | |
parent | 91d1ed1a6d225e3cf4bd8ede6235b1be65f7651a (diff) |
[SPARC64]: Refine Sabre wsync logic.
It is only needed when there is a PCI-PCI bridge sitting
between the device and the PCI host controller which is
not a Simba APB bridge.
Add logic to handle two special cases:
1) device behind EBUS, which sits on PCI
2) PCI controller interrupts
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc64/kernel/prom.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 86cdbd4dbad5..c86007a2aa3f 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -539,23 +539,43 @@ static unsigned long __sabre_onboard_imap_off[] = { ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) -static int parent_is_sabre_or_simba(struct device_node *dp) +static int sabre_device_needs_wsync(struct device_node *dp) { + struct device_node *parent = dp->parent; char *parent_model, *parent_compat; - parent_model = of_get_property(dp->parent, "model", NULL); + /* This traversal up towards the root is meant to + * handle two cases: + * + * 1) non-PCI bus sitting under PCI, such as 'ebus' + * 2) the PCI controller interrupts themselves, which + * will use the sabre_irq_build but do not need + * the DMA synchronization handling + */ + while (parent) { + if (!strcmp(parent->type, "pci")) + break; + parent = parent->parent; + } + + if (!parent) + return 0; + + parent_model = of_get_property(parent, + "model", NULL); if (parent_model && (!strcmp(parent_model, "SUNW,sabre") || !strcmp(parent_model, "SUNW,simba"))) - return 1; + return 0; - parent_compat = of_get_property(dp->parent, "compatible", NULL); + parent_compat = of_get_property(parent, + "compatible", NULL); if (parent_compat && (!strcmp(parent_compat, "pci108e,a000") || !strcmp(parent_compat, "pci108e,a001"))) - return 1; + return 0; - return 0; + return 1; } static unsigned int sabre_irq_build(struct device_node *dp, @@ -602,8 +622,7 @@ static unsigned int sabre_irq_build(struct device_node *dp, * is run. */ regs = of_get_property(dp, "reg", NULL); - if (regs && - !parent_is_sabre_or_simba(dp)) { + if (regs && sabre_device_needs_wsync(dp)) { irq_install_pre_handler(virt_irq, sabre_wsync_handler, (void *) (long) regs->phys_hi, |