diff options
Diffstat (limited to 'arch/powerpc/kernel/pci_32.c')
-rw-r--r-- | arch/powerpc/kernel/pci_32.c | 143 |
1 files changed, 85 insertions, 58 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 2f54cd81dea5..8336deafc624 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c | |||
@@ -736,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* | |||
736 | return NULL; | 736 | return NULL; |
737 | } | 737 | } |
738 | 738 | ||
739 | static int | 739 | static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, |
740 | scan_OF_pci_childs_iterator(struct device_node* node, void* data) | 740 | unsigned int devfn) |
741 | { | 741 | { |
742 | const unsigned int *reg; | 742 | struct device_node *np = NULL; |
743 | u8* fdata = (u8*)data; | 743 | const u32 *reg; |
744 | 744 | unsigned int psize; | |
745 | reg = get_property(node, "reg", NULL); | 745 | |
746 | if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] | 746 | while ((np = of_get_next_child(parent, np)) != NULL) { |
747 | && ((reg[0] >> 16) & 0xff) == fdata[0]) | 747 | reg = get_property(np, "reg", &psize); |
748 | return 1; | 748 | if (reg == NULL || psize < 4) |
749 | return 0; | 749 | continue; |
750 | if (((reg[0] >> 8) & 0xff) == devfn) | ||
751 | return np; | ||
752 | } | ||
753 | return NULL; | ||
750 | } | 754 | } |
751 | 755 | ||
752 | static struct device_node* | 756 | |
753 | scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | 757 | static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus) |
754 | { | 758 | { |
755 | u8 filter_data[2] = {bus, dev_fn}; | 759 | struct device_node *parent, *np; |
760 | |||
761 | /* Are we a root bus ? */ | ||
762 | if (bus->self == NULL || bus->parent == NULL) { | ||
763 | struct pci_controller *hose = pci_bus_to_hose(bus->number); | ||
764 | if (hose == NULL) | ||
765 | return NULL; | ||
766 | return of_node_get(hose->arch_data); | ||
767 | } | ||
768 | |||
769 | /* not a root bus, we need to get our parent */ | ||
770 | parent = scan_OF_for_pci_bus(bus->parent); | ||
771 | if (parent == NULL) | ||
772 | return NULL; | ||
773 | |||
774 | /* now iterate for children for a match */ | ||
775 | np = scan_OF_for_pci_dev(parent, bus->self->devfn); | ||
776 | of_node_put(parent); | ||
756 | 777 | ||
757 | return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); | 778 | /* sanity check */ |
779 | if (strcmp(np->type, "pci") != 0) | ||
780 | printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n", | ||
781 | np->type, np->full_name); | ||
782 | |||
783 | return np; | ||
758 | } | 784 | } |
759 | 785 | ||
760 | /* | 786 | /* |
@@ -763,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | |||
763 | struct device_node * | 789 | struct device_node * |
764 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) | 790 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) |
765 | { | 791 | { |
766 | struct pci_controller *hose; | 792 | struct device_node *parent, *np; |
767 | struct device_node *node; | ||
768 | int busnr; | ||
769 | 793 | ||
770 | if (!have_of) | 794 | if (!have_of) |
771 | return NULL; | 795 | return NULL; |
772 | |||
773 | /* Lookup the hose */ | ||
774 | busnr = bus->number; | ||
775 | hose = pci_bus_to_hose(busnr); | ||
776 | if (!hose) | ||
777 | return NULL; | ||
778 | 796 | ||
779 | /* Check it has an OF node associated */ | 797 | DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn); |
780 | node = (struct device_node *) hose->arch_data; | 798 | parent = scan_OF_for_pci_bus(bus); |
781 | if (!node) | 799 | if (parent == NULL) |
782 | return NULL; | 800 | return NULL; |
783 | 801 | DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>"); | |
784 | /* Fixup bus number according to what OF think it is. */ | 802 | np = scan_OF_for_pci_dev(parent, devfn); |
785 | #ifdef CONFIG_PPC_PMAC | 803 | of_node_put(parent); |
786 | /* The G5 need a special case here. Basically, we don't remap all | 804 | DBG(" result is %s\n", np ? np->full_name : "<NULL>"); |
787 | * busses on it so we don't create the pci-OF-map. However, we do | 805 | |
788 | * remap the AGP bus and so have to deal with it. A future better | 806 | /* XXX most callers don't release the returned node |
789 | * fix has to be done by making the remapping per-host and always | 807 | * mostly because ppc64 doesn't increase the refcount, |
790 | * filling the pci_to_OF map. --BenH | 808 | * we need to fix that. |
791 | */ | 809 | */ |
792 | if (machine_is(powermac) && busnr >= 0xf0) | 810 | return np; |
793 | busnr -= 0xf0; | ||
794 | else | ||
795 | #endif | ||
796 | if (pci_to_OF_bus_map) | ||
797 | busnr = pci_to_OF_bus_map[busnr]; | ||
798 | if (busnr == 0xff) | ||
799 | return NULL; | ||
800 | |||
801 | /* Now, lookup childs of the hose */ | ||
802 | return scan_OF_childs_for_device(node->child, busnr, devfn); | ||
803 | } | 811 | } |
804 | EXPORT_SYMBOL(pci_busdev_to_OF_node); | 812 | EXPORT_SYMBOL(pci_busdev_to_OF_node); |
805 | 813 | ||
@@ -1544,7 +1552,7 @@ pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) | |||
1544 | 1552 | ||
1545 | 1553 | ||
1546 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | 1554 | static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, |
1547 | unsigned long *offset, | 1555 | resource_size_t *offset, |
1548 | enum pci_mmap_state mmap_state) | 1556 | enum pci_mmap_state mmap_state) |
1549 | { | 1557 | { |
1550 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 1558 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
@@ -1556,7 +1564,9 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, | |||
1556 | 1564 | ||
1557 | /* If memory, add on the PCI bridge address offset */ | 1565 | /* If memory, add on the PCI bridge address offset */ |
1558 | if (mmap_state == pci_mmap_mem) { | 1566 | if (mmap_state == pci_mmap_mem) { |
1567 | #if 0 /* See comment in pci_resource_to_user() for why this is disabled */ | ||
1559 | *offset += hose->pci_mem_offset; | 1568 | *offset += hose->pci_mem_offset; |
1569 | #endif | ||
1560 | res_bit = IORESOURCE_MEM; | 1570 | res_bit = IORESOURCE_MEM; |
1561 | } else { | 1571 | } else { |
1562 | io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE; | 1572 | io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE; |
@@ -1624,9 +1634,6 @@ static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, | |||
1624 | else | 1634 | else |
1625 | prot |= _PAGE_GUARDED; | 1635 | prot |= _PAGE_GUARDED; |
1626 | 1636 | ||
1627 | printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev), | ||
1628 | (unsigned long long)rp->start, prot); | ||
1629 | |||
1630 | return __pgprot(prot); | 1637 | return __pgprot(prot); |
1631 | } | 1638 | } |
1632 | 1639 | ||
@@ -1695,7 +1702,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | |||
1695 | enum pci_mmap_state mmap_state, | 1702 | enum pci_mmap_state mmap_state, |
1696 | int write_combine) | 1703 | int write_combine) |
1697 | { | 1704 | { |
1698 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | 1705 | resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; |
1699 | struct resource *rp; | 1706 | struct resource *rp; |
1700 | int ret; | 1707 | int ret; |
1701 | 1708 | ||
@@ -1808,22 +1815,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, | |||
1808 | resource_size_t *start, resource_size_t *end) | 1815 | resource_size_t *start, resource_size_t *end) |
1809 | { | 1816 | { |
1810 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); | 1817 | struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); |
1811 | unsigned long offset = 0; | 1818 | resource_size_t offset = 0; |
1812 | 1819 | ||
1813 | if (hose == NULL) | 1820 | if (hose == NULL) |
1814 | return; | 1821 | return; |
1815 | 1822 | ||
1816 | if (rsrc->flags & IORESOURCE_IO) | 1823 | if (rsrc->flags & IORESOURCE_IO) |
1817 | offset = (void __iomem *)_IO_BASE - hose->io_base_virt | 1824 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; |
1818 | + hose->io_base_phys; | 1825 | |
1826 | /* We pass a fully fixed up address to userland for MMIO instead of | ||
1827 | * a BAR value because X is lame and expects to be able to use that | ||
1828 | * to pass to /dev/mem ! | ||
1829 | * | ||
1830 | * That means that we'll have potentially 64 bits values where some | ||
1831 | * userland apps only expect 32 (like X itself since it thinks only | ||
1832 | * Sparc has 64 bits MMIO) but if we don't do that, we break it on | ||
1833 | * 32 bits CHRPs :-( | ||
1834 | * | ||
1835 | * Hopefully, the sysfs insterface is immune to that gunk. Once X | ||
1836 | * has been fixed (and the fix spread enough), we can re-enable the | ||
1837 | * 2 lines below and pass down a BAR value to userland. In that case | ||
1838 | * we'll also have to re-enable the matching code in | ||
1839 | * __pci_mmap_make_offset(). | ||
1840 | * | ||
1841 | * BenH. | ||
1842 | */ | ||
1843 | #if 0 | ||
1844 | else if (rsrc->flags & IORESOURCE_MEM) | ||
1845 | offset = hose->pci_mem_offset; | ||
1846 | #endif | ||
1819 | 1847 | ||
1820 | *start = rsrc->start + offset; | 1848 | *start = rsrc->start - offset; |
1821 | *end = rsrc->end + offset; | 1849 | *end = rsrc->end - offset; |
1822 | } | 1850 | } |
1823 | 1851 | ||
1824 | void __init | 1852 | void __init pci_init_resource(struct resource *res, resource_size_t start, |
1825 | pci_init_resource(struct resource *res, unsigned long start, unsigned long end, | 1853 | resource_size_t end, int flags, char *name) |
1826 | int flags, char *name) | ||
1827 | { | 1854 | { |
1828 | res->start = start; | 1855 | res->start = start; |
1829 | res->end = end; | 1856 | res->end = end; |