diff options
Diffstat (limited to 'arch/ppc64/kernel/pci.c')
| -rw-r--r-- | arch/ppc64/kernel/pci.c | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index b5ca7d8347e2..8447dcc2c2b3 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
| 22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
| 23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
| 24 | #include <linux/syscalls.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
| 26 | #include <asm/io.h> | 27 | #include <asm/io.h> |
| @@ -837,9 +838,11 @@ int pcibios_scan_all_fns(struct pci_bus *bus, int devfn) | |||
| 837 | * device tree. If they are then we need to scan all the | 838 | * device tree. If they are then we need to scan all the |
| 838 | * functions of this slot. | 839 | * functions of this slot. |
| 839 | */ | 840 | */ |
| 840 | for (dn = busdn->child; dn; dn = dn->sibling) | 841 | for (dn = busdn->child; dn; dn = dn->sibling) { |
| 841 | if ((dn->devfn >> 3) == (devfn >> 3)) | 842 | struct pci_dn *pdn = dn->data; |
| 843 | if (pdn && (pdn->devfn >> 3) == (devfn >> 3)) | ||
| 842 | return 1; | 844 | return 1; |
| 845 | } | ||
| 843 | 846 | ||
| 844 | return 0; | 847 | return 0; |
| 845 | } | 848 | } |
| @@ -982,3 +985,62 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, | |||
| 982 | } | 985 | } |
| 983 | 986 | ||
| 984 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 987 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
| 988 | |||
| 989 | |||
| 990 | #define IOBASE_BRIDGE_NUMBER 0 | ||
| 991 | #define IOBASE_MEMORY 1 | ||
| 992 | #define IOBASE_IO 2 | ||
| 993 | #define IOBASE_ISA_IO 3 | ||
| 994 | #define IOBASE_ISA_MEM 4 | ||
| 995 | |||
| 996 | long sys_pciconfig_iobase(long which, unsigned long in_bus, | ||
| 997 | unsigned long in_devfn) | ||
| 998 | { | ||
| 999 | struct pci_controller* hose; | ||
| 1000 | struct list_head *ln; | ||
| 1001 | struct pci_bus *bus = NULL; | ||
| 1002 | struct device_node *hose_node; | ||
| 1003 | |||
| 1004 | /* Argh ! Please forgive me for that hack, but that's the | ||
| 1005 | * simplest way to get existing XFree to not lockup on some | ||
| 1006 | * G5 machines... So when something asks for bus 0 io base | ||
| 1007 | * (bus 0 is HT root), we return the AGP one instead. | ||
| 1008 | */ | ||
| 1009 | #ifdef CONFIG_PPC_PMAC | ||
| 1010 | if (systemcfg->platform == PLATFORM_POWERMAC && | ||
| 1011 | machine_is_compatible("MacRISC4")) | ||
| 1012 | if (in_bus == 0) | ||
| 1013 | in_bus = 0xf0; | ||
| 1014 | #endif /* CONFIG_PPC_PMAC */ | ||
| 1015 | |||
| 1016 | /* That syscall isn't quite compatible with PCI domains, but it's | ||
| 1017 | * used on pre-domains setup. We return the first match | ||
| 1018 | */ | ||
| 1019 | |||
| 1020 | for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { | ||
| 1021 | bus = pci_bus_b(ln); | ||
| 1022 | if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate)) | ||
| 1023 | break; | ||
| 1024 | bus = NULL; | ||
| 1025 | } | ||
| 1026 | if (bus == NULL || bus->sysdata == NULL) | ||
| 1027 | return -ENODEV; | ||
| 1028 | |||
| 1029 | hose_node = (struct device_node *)bus->sysdata; | ||
| 1030 | hose = PCI_DN(hose_node)->phb; | ||
| 1031 | |||
| 1032 | switch (which) { | ||
| 1033 | case IOBASE_BRIDGE_NUMBER: | ||
| 1034 | return (long)hose->first_busno; | ||
| 1035 | case IOBASE_MEMORY: | ||
| 1036 | return (long)hose->pci_mem_offset; | ||
| 1037 | case IOBASE_IO: | ||
| 1038 | return (long)hose->io_base_phys; | ||
| 1039 | case IOBASE_ISA_IO: | ||
| 1040 | return (long)isa_io_base; | ||
| 1041 | case IOBASE_ISA_MEM: | ||
| 1042 | return -EINVAL; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | return -EOPNOTSUPP; | ||
| 1046 | } | ||
