Commit 9bbd952e7f965757b5c913b6f98ad37a191137bd
1 parent
91d1ed1a6d
Exists in
master
and in
4 other branches
[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>
Showing 1 changed file with 27 additions and 8 deletions Side-by-side Diff
arch/sparc64/kernel/prom.c
| ... | ... | @@ -539,23 +539,43 @@ |
| 539 | 539 | ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ |
| 540 | 540 | (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) |
| 541 | 541 | |
| 542 | -static int parent_is_sabre_or_simba(struct device_node *dp) | |
| 542 | +static int sabre_device_needs_wsync(struct device_node *dp) | |
| 543 | 543 | { |
| 544 | + struct device_node *parent = dp->parent; | |
| 544 | 545 | char *parent_model, *parent_compat; |
| 545 | 546 | |
| 546 | - parent_model = of_get_property(dp->parent, "model", NULL); | |
| 547 | + /* This traversal up towards the root is meant to | |
| 548 | + * handle two cases: | |
| 549 | + * | |
| 550 | + * 1) non-PCI bus sitting under PCI, such as 'ebus' | |
| 551 | + * 2) the PCI controller interrupts themselves, which | |
| 552 | + * will use the sabre_irq_build but do not need | |
| 553 | + * the DMA synchronization handling | |
| 554 | + */ | |
| 555 | + while (parent) { | |
| 556 | + if (!strcmp(parent->type, "pci")) | |
| 557 | + break; | |
| 558 | + parent = parent->parent; | |
| 559 | + } | |
| 560 | + | |
| 561 | + if (!parent) | |
| 562 | + return 0; | |
| 563 | + | |
| 564 | + parent_model = of_get_property(parent, | |
| 565 | + "model", NULL); | |
| 547 | 566 | if (parent_model && |
| 548 | 567 | (!strcmp(parent_model, "SUNW,sabre") || |
| 549 | 568 | !strcmp(parent_model, "SUNW,simba"))) |
| 550 | - return 1; | |
| 569 | + return 0; | |
| 551 | 570 | |
| 552 | - parent_compat = of_get_property(dp->parent, "compatible", NULL); | |
| 571 | + parent_compat = of_get_property(parent, | |
| 572 | + "compatible", NULL); | |
| 553 | 573 | if (parent_compat && |
| 554 | 574 | (!strcmp(parent_compat, "pci108e,a000") || |
| 555 | 575 | !strcmp(parent_compat, "pci108e,a001"))) |
| 556 | - return 1; | |
| 576 | + return 0; | |
| 557 | 577 | |
| 558 | - return 0; | |
| 578 | + return 1; | |
| 559 | 579 | } |
| 560 | 580 | |
| 561 | 581 | static unsigned int sabre_irq_build(struct device_node *dp, |
| ... | ... | @@ -602,8 +622,7 @@ |
| 602 | 622 | * is run. |
| 603 | 623 | */ |
| 604 | 624 | regs = of_get_property(dp, "reg", NULL); |
| 605 | - if (regs && | |
| 606 | - !parent_is_sabre_or_simba(dp)) { | |
| 625 | + if (regs && sabre_device_needs_wsync(dp)) { | |
| 607 | 626 | irq_install_pre_handler(virt_irq, |
| 608 | 627 | sabre_wsync_handler, |
| 609 | 628 | (void *) (long) regs->phys_hi, |