diff options
-rw-r--r-- | drivers/parisc/lba_pci.c | 113 |
1 files changed, 90 insertions, 23 deletions
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 4f6bdf0881b5..cbae8c8963fa 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c | |||
@@ -695,11 +695,71 @@ lba_claim_dev_resources(struct pci_dev *dev) | |||
695 | } | 695 | } |
696 | } | 696 | } |
697 | } | 697 | } |
698 | |||
699 | |||
700 | /* | ||
701 | * truncate_pat_collision: Deal with overlaps or outright collisions | ||
702 | * between PAT PDC reported ranges. | ||
703 | * | ||
704 | * Broken PA8800 firmware will report lmmio range that | ||
705 | * overlaps with CPU HPA. Just truncate the lmmio range. | ||
706 | * | ||
707 | * BEWARE: conflicts with this lmmio range may be an | ||
708 | * elmmio range which is pointing down another rope. | ||
709 | * | ||
710 | * FIXME: only deals with one collision per range...theoretically we | ||
711 | * could have several. Supporting more than one collision will get messy. | ||
712 | */ | ||
713 | static unsigned long | ||
714 | truncate_pat_collision(struct resource *root, struct resource *new) | ||
715 | { | ||
716 | unsigned long start = new->start; | ||
717 | unsigned long end = new->end; | ||
718 | struct resource *tmp = root->child; | ||
719 | |||
720 | if (end <= start || start < root->start || !tmp) | ||
721 | return 0; | ||
722 | |||
723 | /* find first overlap */ | ||
724 | while (tmp && tmp->end < start) | ||
725 | tmp = tmp->sibling; | ||
726 | |||
727 | /* no entries overlap */ | ||
728 | if (!tmp) return 0; | ||
729 | |||
730 | /* found one that starts behind the new one | ||
731 | ** Don't need to do anything. | ||
732 | */ | ||
733 | if (tmp->start >= end) return 0; | ||
734 | |||
735 | if (tmp->start <= start) { | ||
736 | /* "front" of new one overlaps */ | ||
737 | new->start = tmp->end + 1; | ||
738 | |||
739 | if (tmp->end >= end) { | ||
740 | /* AACCKK! totally overlaps! drop this range. */ | ||
741 | return 1; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | if (tmp->end < end ) { | ||
746 | /* "end" of new one overlaps */ | ||
747 | new->end = tmp->start - 1; | ||
748 | } | ||
749 | |||
750 | printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] " | ||
751 | "to [%lx,%lx]\n", | ||
752 | start, end, | ||
753 | new->start, new->end ); | ||
754 | |||
755 | return 0; /* truncation successful */ | ||
756 | } | ||
757 | |||
698 | #else | 758 | #else |
699 | #define lba_claim_dev_resources(dev) | 759 | #define lba_claim_dev_resources(dev) do { } while (0) |
760 | #define truncate_pat_collision(r,n) (0) | ||
700 | #endif | 761 | #endif |
701 | 762 | ||
702 | |||
703 | /* | 763 | /* |
704 | ** The algorithm is generic code. | 764 | ** The algorithm is generic code. |
705 | ** But it needs to access local data structures to get the IRQ base. | 765 | ** But it needs to access local data structures to get the IRQ base. |
@@ -747,6 +807,9 @@ lba_fixup_bus(struct pci_bus *bus) | |||
747 | lba_dump_res(&ioport_resource, 2); | 807 | lba_dump_res(&ioport_resource, 2); |
748 | BUG(); | 808 | BUG(); |
749 | } | 809 | } |
810 | /* advertize Host bridge resources to PCI bus */ | ||
811 | bus->resource[0] = &(ldev->hba.io_space); | ||
812 | i = 1; | ||
750 | 813 | ||
751 | if (ldev->hba.elmmio_space.start) { | 814 | if (ldev->hba.elmmio_space.start) { |
752 | err = request_resource(&iomem_resource, | 815 | err = request_resource(&iomem_resource, |
@@ -760,23 +823,35 @@ lba_fixup_bus(struct pci_bus *bus) | |||
760 | 823 | ||
761 | /* lba_dump_res(&iomem_resource, 2); */ | 824 | /* lba_dump_res(&iomem_resource, 2); */ |
762 | /* BUG(); */ | 825 | /* BUG(); */ |
763 | } | 826 | } else |
827 | bus->resource[i++] = &(ldev->hba.elmmio_space); | ||
764 | } | 828 | } |
765 | 829 | ||
766 | err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); | 830 | |
767 | if (err < 0) { | 831 | /* Overlaps with elmmio can (and should) fail here. |
768 | /* FIXME overlaps with elmmio will fail here. | 832 | * We will prune (or ignore) the distributed range. |
769 | * Need to prune (or disable) the distributed range. | 833 | * |
770 | * | 834 | * FIXME: SBA code should register all elmmio ranges first. |
771 | * BEWARE: conflicts with this lmmio range may be | 835 | * that would take care of elmmio ranges routed |
772 | * elmmio range which is pointing down another rope. | 836 | * to a different rope (already discovered) from |
773 | */ | 837 | * getting registered *after* LBA code has already |
774 | 838 | * registered it's distributed lmmio range. | |
775 | printk("FAILED: lba_fixup_bus() request for " | 839 | */ |
840 | if (truncate_pat_collision(&iomem_resource, | ||
841 | &(ldev->hba.lmmio_space))) { | ||
842 | |||
843 | printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n", | ||
844 | ldev->hba.lmmio_space.start, | ||
845 | ldev->hba.lmmio_space.end); | ||
846 | } else { | ||
847 | err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); | ||
848 | if (err < 0) { | ||
849 | printk(KERN_ERR "FAILED: lba_fixup_bus() request for " | ||
776 | "lmmio_space [%lx/%lx]\n", | 850 | "lmmio_space [%lx/%lx]\n", |
777 | ldev->hba.lmmio_space.start, | 851 | ldev->hba.lmmio_space.start, |
778 | ldev->hba.lmmio_space.end); | 852 | ldev->hba.lmmio_space.end); |
779 | /* lba_dump_res(&iomem_resource, 2); */ | 853 | } else |
854 | bus->resource[i++] = &(ldev->hba.lmmio_space); | ||
780 | } | 855 | } |
781 | 856 | ||
782 | #ifdef CONFIG_64BIT | 857 | #ifdef CONFIG_64BIT |
@@ -791,18 +866,10 @@ lba_fixup_bus(struct pci_bus *bus) | |||
791 | lba_dump_res(&iomem_resource, 2); | 866 | lba_dump_res(&iomem_resource, 2); |
792 | BUG(); | 867 | BUG(); |
793 | } | 868 | } |
869 | bus->resource[i++] = &(ldev->hba.gmmio_space); | ||
794 | } | 870 | } |
795 | #endif | 871 | #endif |
796 | 872 | ||
797 | /* advertize Host bridge resources to PCI bus */ | ||
798 | bus->resource[0] = &(ldev->hba.io_space); | ||
799 | bus->resource[1] = &(ldev->hba.lmmio_space); | ||
800 | i=2; | ||
801 | if (ldev->hba.elmmio_space.start) | ||
802 | bus->resource[i++] = &(ldev->hba.elmmio_space); | ||
803 | if (ldev->hba.gmmio_space.start) | ||
804 | bus->resource[i++] = &(ldev->hba.gmmio_space); | ||
805 | |||
806 | } | 873 | } |
807 | 874 | ||
808 | list_for_each(ln, &bus->devices) { | 875 | list_for_each(ln, &bus->devices) { |