aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/parisc/lba_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/parisc/lba_pci.c')
-rw-r--r--drivers/parisc/lba_pci.c115
1 files changed, 91 insertions, 24 deletions
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 5e495dcbc58a..cbae8c8963fa 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -167,7 +167,7 @@
167 167
168/* non-postable I/O port space, densely packed */ 168/* non-postable I/O port space, densely packed */
169#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL) 169#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)
170static void __iomem *astro_iop_base; 170static void __iomem *astro_iop_base __read_mostly;
171 171
172#define ELROY_HVERS 0x782 172#define ELROY_HVERS 0x782
173#define MERCURY_HVERS 0x783 173#define MERCURY_HVERS 0x783
@@ -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 */
713static unsigned long
714truncate_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) {