diff options
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/Kconfig | 8 | ||||
-rw-r--r-- | arch/microblaze/configs/mmu_defconfig | 1 | ||||
-rw-r--r-- | arch/microblaze/include/asm/pci-bridge.h | 92 | ||||
-rw-r--r-- | arch/microblaze/include/asm/pci.h | 29 | ||||
-rw-r--r-- | arch/microblaze/include/asm/pgtable.h | 3 | ||||
-rw-r--r-- | arch/microblaze/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/microblaze/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/microblaze/pci/indirect_pci.c | 158 | ||||
-rw-r--r-- | arch/microblaze/pci/iomap.c | 36 | ||||
-rw-r--r-- | arch/microblaze/pci/pci-common.c | 1067 | ||||
-rw-r--r-- | arch/microblaze/pci/xilinx_pci.c | 170 |
11 files changed, 38 insertions, 1531 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 4ebb56d6d959..cc88af6fa7a4 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -215,11 +215,3 @@ config MB_MANAGER Say N here unless you know what you are doing. endmenu - -menu "Bus Options" - -config PCI_XILINX - bool "Xilinx PCI host bridge support" - depends on PCI - -endmenu diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig index 8150daf04a76..756feb9369a6 100644 --- a/arch/microblaze/configs/mmu_defconfig +++ b/arch/microblaze/configs/mmu_defconfig @@ -19,7 +19,6 @@ CONFIG_HZ_100=y CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE_FORCE=y CONFIG_HIGHMEM=y -CONFIG_PCI_XILINX=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h index 171b40a2d905..be5f504bead4 100644 --- a/arch/microblaze/include/asm/pci-bridge.h +++ b/arch/microblaze/include/asm/pci-bridge.h @@ -25,75 +25,17 @@ static inline int pcibios_vaddr_is_ioport(void __iomem *address) */ struct pci_controller { struct pci_bus *bus; - char is_dynamic; - struct device_node *dn; struct list_head list_node; - struct device *parent; - - int first_busno; - int last_busno; - - int self_busno; void __iomem *io_base_virt; - resource_size_t io_base_phys; - - resource_size_t pci_io_size; - - /* Some machines (PReP) have a non 1:1 mapping of - * the PCI memory space in the CPU bus space - */ - resource_size_t pci_mem_offset; - - /* Some machines have a special region to forward the ISA - * "memory" cycles such as VGA memory regions. Left to 0 - * if unsupported - */ - resource_size_t isa_mem_phys; - resource_size_t isa_mem_size; - - struct pci_ops *ops; - unsigned int __iomem *cfg_addr; - void __iomem *cfg_data; - - /* - * Used for variants of PCI indirect handling and possible quirks: - * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1 - * EXT_REG - provides access to PCI-e extended registers - * SURPRESS_PRIMARY_BUS - we suppress the setting of PCI_PRIMARY_BUS - * on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS - * to determine which bus number to match on when generating type0 - * config cycles - * NO_PCIE_LINK - the Freescale PCI-e controllers have issues with - * hanging if we don't have link and try to do config cycles to - * anything but the PHB. Only allow talking to the PHB if this is - * set. - * BIG_ENDIAN - cfg_addr is a big endian register - * BROKEN_MRM - the 440EPx/GRx chips have an errata that causes hangs - * on the PLB4. Effectively disable MRM commands by setting this. - */ -#define INDIRECT_TYPE_SET_CFG_TYPE 0x00000001 -#define INDIRECT_TYPE_EXT_REG 0x00000002 -#define INDIRECT_TYPE_SURPRESS_PRIMARY_BUS 0x00000004 -#define INDIRECT_TYPE_NO_PCIE_LINK 0x00000008 -#define INDIRECT_TYPE_BIG_ENDIAN 0x00000010 -#define INDIRECT_TYPE_BROKEN_MRM 0x00000020 - u32 indirect_type; /* Currently, we limit ourselves to 1 IO range and 3 mem * ranges since the common pci_bus structure can't handle more */ struct resource io_resource; - struct resource mem_resources[3]; - int global_number; /* PCI domain number */ }; #ifdef CONFIG_PCI -static inline struct pci_controller *pci_bus_to_host(const struct pci_bus *bus) -{ - return bus->sysdata; -} - static inline int isa_vaddr_is_ioport(void __iomem *address) { /* No specific ISA handling on ppc32 at this stage, it @@ -103,39 +45,5 @@ static inline int isa_vaddr_is_ioport(void __iomem *address) } #endif /* CONFIG_PCI */ -/* These are used for config access before all the PCI probing - has been done. */ -extern int early_read_config_byte(struct pci_controller *hose, int bus, - int dev_fn, int where, u8 *val); -extern int early_read_config_word(struct pci_controller *hose, int bus, - int dev_fn, int where, u16 *val); -extern int early_read_config_dword(struct pci_controller *hose, int bus, - int dev_fn, int where, u32 *val); -extern int early_write_config_byte(struct pci_controller *hose, int bus, - int dev_fn, int where, u8 val); -extern int early_write_config_word(struct pci_controller *hose, int bus, - int dev_fn, int where, u16 val); -extern int early_write_config_dword(struct pci_controller *hose, int bus, - int dev_fn, int where, u32 val); - -extern int early_find_capability(struct pci_controller *hose, int bus, - int dev_fn, int cap); - -extern void setup_indirect_pci(struct pci_controller *hose, - resource_size_t cfg_addr, - resource_size_t cfg_data, u32 flags); - -/* Get the PCI host controller for an OF device */ -extern struct pci_controller *pci_find_hose_for_OF_device( - struct device_node *node); - -/* Fill up host controller resources from the OF node */ -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary); - -/* Allocate & free a PCI host bridge structure */ -extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); -extern void pcibios_free_controller(struct pci_controller *phb); - #endif /* __KERNEL__ */ #endif /* _ASM_MICROBLAZE_PCI_BRIDGE_H */ diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h index d90528064604..91f1f71c266a 100644 --- a/arch/microblaze/include/asm/pci.h +++ b/arch/microblaze/include/asm/pci.h @@ -21,15 +21,6 @@ #define PCIBIOS_MIN_IO 0x1000 #define PCIBIOS_MIN_MEM 0x10000000 -/* Values for the `which' argument to sys_pciconfig_iobase syscall. */ -#define IOBASE_BRIDGE_NUMBER 0 -#define IOBASE_MEMORY 1 -#define IOBASE_IO 2 -#define IOBASE_ISA_IO 3 -#define IOBASE_ISA_MEM 4 - -#define pcibios_scan_all_fns(a, b) 0 - /* * Set this to 1 if you want the kernel to re-assign all PCI * bus numbers (don't do that on ppc64 yet !) @@ -41,33 +32,13 @@ extern int pci_domain_nr(struct pci_bus *bus); /* Decide whether to display the domain number in /proc */ extern int pci_proc_domain(struct pci_bus *bus); -struct vm_area_struct; - /* Tell PCI code what kind of PCI resource mappings we support */ #define HAVE_PCI_MMAP 1 #define ARCH_GENERIC_PCI_MMAP_RESOURCE 1 -#define arch_can_pci_mmap_io() 1 - -extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, - size_t count); -extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, - size_t count); -extern int pci_mmap_legacy_page_range(struct pci_bus *bus, - struct vm_area_struct *vma, - enum pci_mmap_state mmap_state); - -#define HAVE_PCI_LEGACY 1 - -extern void pcibios_resource_survey(void); struct file; -/* This part of code was originally in xilinx-pci.h */ -#ifdef CONFIG_PCI_XILINX -extern void __init xilinx_pci_init(void); -#else static inline void __init xilinx_pci_init(void) { return; } -#endif #endif /* __KERNEL__ */ #endif /* __ASM_MICROBLAZE_PCI_H */ diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index ba348e997dbb..42f5988e998b 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h @@ -416,9 +416,6 @@ extern unsigned long iopa(unsigned long addr); #define IOMAP_NOCACHE_NONSER 2 #define IOMAP_NO_COPYBACK 3 -/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ -#define kern_addr_valid(addr) (1) - void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 3c6241bcaea8..1f802aab2b96 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -133,7 +133,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) /* * Set up a thread for executing a new program */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu) { return 0; /* MicroBlaze has no separate FPU registers */ } diff --git a/arch/microblaze/pci/Makefile b/arch/microblaze/pci/Makefile index 0251c20e1d62..f8267d20e067 100644 --- a/arch/microblaze/pci/Makefile +++ b/arch/microblaze/pci/Makefile @@ -3,5 +3,4 @@ # Makefile # -obj-$(CONFIG_PCI) += pci-common.o indirect_pci.o iomap.o -obj-$(CONFIG_PCI_XILINX) += xilinx_pci.o +obj-$(CONFIG_PCI) += iomap.o diff --git a/arch/microblaze/pci/indirect_pci.c b/arch/microblaze/pci/indirect_pci.c deleted file mode 100644 index 1caf7d3e0eef..000000000000 --- a/arch/microblaze/pci/indirect_pci.c +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Support for indirect PCI bridges. - * - * Copyright (C) 1998 Gabriel Paubert. - */ - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> - -#include <linux/io.h> -#include <asm/pci-bridge.h> - -static int -indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - volatile void __iomem *cfg_data; - u8 cfg_type = 0; - u32 bus_no, reg; - - if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) { - if (bus->number != hose->first_busno) - return PCIBIOS_DEVICE_NOT_FOUND; - if (devfn != 0) - return PCIBIOS_DEVICE_NOT_FOUND; - } - - if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE) - if (bus->number != hose->first_busno) - cfg_type = 1; - - bus_no = (bus->number == hose->first_busno) ? - hose->self_busno : bus->number; - - if (hose->indirect_type & INDIRECT_TYPE_EXT_REG) - reg = ((offset & 0xf00) << 16) | (offset & 0xfc); - else - reg = offset & 0xfc; /* Only 3 bits for function */ - - if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN) - out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | - (devfn << 8) | reg | cfg_type)); - else - out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | - (devfn << 8) | reg | cfg_type)); - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + (offset & 3); /* Only 3 bits for function */ - switch (len) { - case 1: - *val = in_8(cfg_data); - break; - case 2: - *val = in_le16(cfg_data); - break; - default: - *val = in_le32(cfg_data); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static int -indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - volatile void __iomem *cfg_data; - u8 cfg_type = 0; - u32 bus_no, reg; - - if (hose->indirect_type & INDIRECT_TYPE_NO_PCIE_LINK) { - if (bus->number != hose->first_busno) - return PCIBIOS_DEVICE_NOT_FOUND; - if (devfn != 0) - return PCIBIOS_DEVICE_NOT_FOUND; - } - - if (hose->indirect_type & INDIRECT_TYPE_SET_CFG_TYPE) - if (bus->number != hose->first_busno) - cfg_type = 1; - - bus_no = (bus->number == hose->first_busno) ? - hose->self_busno : bus->number; - - if (hose->indirect_type & INDIRECT_TYPE_EXT_REG) - reg = ((offset & 0xf00) << 16) | (offset & 0xfc); - else - reg = offset & 0xfc; - - if (hose->indirect_type & INDIRECT_TYPE_BIG_ENDIAN) - out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | - (devfn << 8) | reg | cfg_type)); - else - out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | - (devfn << 8) | reg | cfg_type)); - - /* suppress setting of PCI_PRIMARY_BUS */ - if (hose->indirect_type & INDIRECT_TYPE_SURPRESS_PRIMARY_BUS) - if ((offset == PCI_PRIMARY_BUS) && - (bus->number == hose->first_busno)) - val &= 0xffffff00; - - /* Workaround for PCI_28 Errata in 440EPx/GRx */ - if ((hose->indirect_type & INDIRECT_TYPE_BROKEN_MRM) && - offset == PCI_CACHE_LINE_SIZE) { - val = 0; - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + (offset & 3); - switch (len) { - case 1: - out_8(cfg_data, val); - break; - case 2: - out_le16(cfg_data, val); - break; - default: - out_le32(cfg_data, val); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops indirect_pci_ops = { - .read = indirect_read_config, - .write = indirect_write_config, -}; - -void __init -setup_indirect_pci(struct pci_controller *hose, - resource_size_t cfg_addr, - resource_size_t cfg_data, u32 flags) -{ - resource_size_t base = cfg_addr & PAGE_MASK; - void __iomem *mbase; - - mbase = ioremap(base, PAGE_SIZE); - hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK); - if ((cfg_data & PAGE_MASK) != base) - mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); - hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK); - hose->ops = &indirect_pci_ops; - hose->indirect_type = flags; -} diff --git a/arch/microblaze/pci/iomap.c b/arch/microblaze/pci/iomap.c index bde74af4c1cd..b2ee8ace9b6e 100644 --- a/arch/microblaze/pci/iomap.c +++ b/arch/microblaze/pci/iomap.c @@ -11,6 +11,42 @@ #include <linux/io.h> #include <asm/pci-bridge.h> +static DEFINE_SPINLOCK(hose_spinlock); +LIST_HEAD(hose_list); + +unsigned long isa_io_base; +EXPORT_SYMBOL(isa_io_base); + +static resource_size_t pcibios_io_size(const struct pci_controller *hose) +{ + return resource_size(&hose->io_resource); +} + +int pcibios_vaddr_is_ioport(void __iomem *address) +{ + int ret = 0; + struct pci_controller *hose; + resource_size_t size; + + spin_lock(&hose_spinlock); + list_for_each_entry(hose, &hose_list, list_node) { + size = pcibios_io_size(hose); + if (address >= hose->io_base_virt && + address < (hose->io_base_virt + size)) { + ret = 1; + break; + } + } + spin_unlock(&hose_spinlock); + return ret; +} + +/* Display the domain number in /proc */ +int pci_proc_domain(struct pci_bus *bus) +{ + return pci_domain_nr(bus); +} + void pci_iounmap(struct pci_dev *dev, void __iomem *addr) { if (isa_vaddr_is_ioport(addr)) diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c deleted file mode 100644 index 33bab7eec731..000000000000 --- a/arch/microblaze/pci/pci-common.c +++ /dev/null @@ -1,1067 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Contains common pci routines for ALL ppc platform - * (based on pci_32.c and pci_64.c) - * - * Port for PPC64 David Engebretsen, IBM Corp. - * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. - * - * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM - * Rework, based on alpha PCI code. - * - * Common pmac/prep/chrp pci routines. -- Cort - */ - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/memblock.h> -#include <linux/mm.h> -#include <linux/shmem_fs.h> -#include <linux/list.h> -#include <linux/syscalls.h> -#include <linux/irq.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_pci.h> -#include <linux/export.h> - -#include <asm/processor.h> -#include <linux/io.h> -#include <asm/pci-bridge.h> -#include <asm/byteorder.h> - -static DEFINE_SPINLOCK(hose_spinlock); -LIST_HEAD(hose_list); - -/* XXX kill that some day ... */ -static int global_phb_number; /* Global phb counter */ - -/* ISA Memory physical address */ -resource_size_t isa_mem_base; - -unsigned long isa_io_base; -EXPORT_SYMBOL(isa_io_base); - -static int pci_bus_count; - -struct pci_controller *pcibios_alloc_controller(struct device_node *dev) -{ - struct pci_controller *phb; - - phb = zalloc_maybe_bootmem(sizeof(struct pci_controller), GFP_KERNEL); - if (!phb) - return NULL; - spin_lock(&hose_spinlock); - phb->global_number = global_phb_number++; - list_add_tail(&phb->list_node, &hose_list); - spin_unlock(&hose_spinlock); - phb->dn = dev; - phb->is_dynamic = mem_init_done; - return phb; -} - -void pcibios_free_controller(struct pci_controller *phb) -{ - spin_lock(&hose_spinlock); - list_del(&phb->list_node); - spin_unlock(&hose_spinlock); - - if (phb->is_dynamic) - kfree(phb); -} - -static resource_size_t pcibios_io_size(const struct pci_controller *hose) -{ - return resource_size(&hose->io_resource); -} - -int pcibios_vaddr_is_ioport(void __iomem *address) -{ - int ret = 0; - struct pci_controller *hose; - resource_size_t size; - - spin_lock(&hose_spinlock); - list_for_each_entry(hose, &hose_list, list_node) { - size = pcibios_io_size(hose); - if (address >= hose->io_base_virt && - address < (hose->io_base_virt + size)) { - ret = 1; - break; - } - } - spin_unlock(&hose_spinlock); - return ret; -} - -unsigned long pci_address_to_pio(phys_addr_t address) -{ - struct pci_controller *hose; - resource_size_t size; - unsigned long ret = ~0; - - spin_lock(&hose_spinlock); - list_for_each_entry(hose, &hose_list, list_node) { - size = pcibios_io_size(hose); - if (address >= hose->io_base_phys && - address < (hose->io_base_phys + size)) { - unsigned long base = - (unsigned long)hose->io_base_virt - _IO_BASE; - ret = base + (address - hose->io_base_phys); - break; - } - } - spin_unlock(&hose_spinlock); - - return ret; -} -EXPORT_SYMBOL_GPL(pci_address_to_pio); - -/* This routine is meant to be used early during boot, when the - * PCI bus numbers have not yet been assigned, and you need to - * issue PCI config cycles to an OF device. - * It could also be used to "fix" RTAS config cycles if you want - * to set pci_assign_all_buses to 1 and still use RTAS for PCI - * config cycles. - */ -struct pci_controller *pci_find_hose_for_OF_device(struct device_node *node) -{ - while (node) { - struct pci_controller *hose, *tmp; - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) - if (hose->dn == node) - return hose; - node = node->parent; - } - return NULL; -} - -void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - -/* - * Platform support for /proc/bus/pci/X/Y mmap()s. - */ - -int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma) -{ - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - resource_size_t ioaddr = pci_resource_start(pdev, bar); - - if (!hose) - return -EINVAL; /* should never happen */ - - /* Convert to an offset within this PCI controller */ - ioaddr -= (unsigned long)hose->io_base_virt - _IO_BASE; - - vma->vm_pgoff += (ioaddr + hose->io_base_phys) >> PAGE_SHIFT; - return 0; -} - -/* This provides legacy IO read access on a bus */ -int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size) -{ - unsigned long offset; - struct pci_controller *hose = pci_bus_to_host(bus); - struct resource *rp = &hose->io_resource; - void __iomem *addr; - - /* Check if port can be supported by that bus. We only check - * the ranges of the PHB though, not the bus itself as the rules - * for forwarding legacy cycles down bridges are not our problem - * here. So if the host bridge supports it, we do it. - */ - offset = (unsigned long)hose->io_base_virt - _IO_BASE; - offset += port; - - if (!(rp->flags & IORESOURCE_IO)) - return -ENXIO; - if (offset < rp->start || (offset + size) > rp->end) - return -ENXIO; - addr = hose->io_base_virt + port; - - switch (size) { - case 1: - *((u8 *)val) = in_8(addr); - return 1; - case 2: - if (port & 1) - return -EINVAL; - *((u16 *)val) = in_le16(addr); - return 2; - case 4: - if (port & 3) - return -EINVAL; - *((u32 *)val) = in_le32(addr); - return 4; - } - return -EINVAL; -} - -/* This provides legacy IO write access on a bus */ -int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size) -{ - unsigned long offset; - struct pci_controller *hose = pci_bus_to_host(bus); - struct resource *rp = &hose->io_resource; - void __iomem *addr; - - /* Check if port can be supported by that bus. We only check - * the ranges of the PHB though, not the bus itself as the rules - * for forwarding legacy cycles down bridges are not our problem - * here. So if the host bridge supports it, we do it. - */ - offset = (unsigned long)hose->io_base_virt - _IO_BASE; - offset += port; - - if (!(rp->flags & IORESOURCE_IO)) - return -ENXIO; - if (offset < rp->start || (offset + size) > rp->end) - return -ENXIO; - addr = hose->io_base_virt + port; - - /* WARNING: The generic code is idiotic. It gets passed a pointer - * to what can be a 1, 2 or 4 byte quantity and always reads that - * as a u32, which means that we have to correct the location of - * the data read within those 32 bits for size 1 and 2 - */ - switch (size) { - case 1: - out_8(addr, val >> 24); - return 1; - case 2: - if (port & 1) - return -EINVAL; - out_le16(addr, val >> 16); - return 2; - case 4: - if (port & 3) - return -EINVAL; - out_le32(addr, val); - return 4; - } - return -EINVAL; -} - -/* This provides legacy IO or memory mmap access on a bus */ -int pci_mmap_legacy_page_range(struct pci_bus *bus, - struct vm_area_struct *vma, - enum pci_mmap_state mmap_state) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - resource_size_t offset = - ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT; - resource_size_t size = vma->vm_end - vma->vm_start; - struct resource *rp; - - pr_debug("pci_mmap_legacy_page_range(%04x:%02x, %s @%llx..%llx)\n", - pci_domain_nr(bus), bus->number, - mmap_state == pci_mmap_mem ? "MEM" : "IO", - (unsigned long long)offset, - (unsigned long long)(offset + size - 1)); - - if (mmap_state == pci_mmap_mem) { - /* Hack alert ! - * - * Because X is lame and can fail starting if it gets an error - * trying to mmap legacy_mem (instead of just moving on without - * legacy memory access) we fake it here by giving it anonymous - * memory, effectively behaving just like /dev/zero - */ - if ((offset + size) > hose->isa_mem_size) { - pr_debug("Process %s (pid:%d) mapped non-existing PCI", - current->comm, current->pid); - pr_debug("legacy memory for 0%04x:%02x\n", - pci_domain_nr(bus), bus->number); - if (vma->vm_flags & VM_SHARED) - return shmem_zero_setup(vma); - return 0; - } - offset += hose->isa_mem_phys; - } else { - unsigned long io_offset = (unsigned long)hose->io_base_virt - - _IO_BASE; - unsigned long roffset = offset + io_offset; - rp = &hose->io_resource; - if (!(rp->flags & IORESOURCE_IO)) - return -ENXIO; - if (roffset < rp->start || (roffset + size) > rp->end) - return -ENXIO; - offset += hose->io_base_phys; - } - pr_debug(" -> mapping phys %llx\n", (unsigned long long)offset); - - vma->vm_pgoff = offset >> PAGE_SHIFT; - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); -} - -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end) -{ - struct pci_bus_region region; - - if (rsrc->flags & IORESOURCE_IO) { - pcibios_resource_to_bus(dev->bus, ®ion, - (struct resource *) rsrc); - *start = region.start; - *end = region.end; - return; - } - - /* We pass a CPU physical address to userland for MMIO instead of a - * BAR value because X is lame and expects to be able to use that - * to pass to /dev/mem! - * - * That means we may have 64-bit values where some apps only expect - * 32 (like X itself since it thinks only Sparc has 64-bit MMIO). - */ - *start = rsrc->start; - *end = rsrc->end; -} - -/** - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree - * @hose: newly allocated pci_controller to be setup - * @dev: device node of the host bridge - * @primary: set if primary bus (32 bits only, soon to be deprecated) - * - * This function will parse the "ranges" property of a PCI host bridge device - * node and setup the resource mapping of a pci controller based on its - * content. - * - * Life would be boring if it wasn't for a few issues that we have to deal - * with here: - * - * - We can only cope with one IO space range and up to 3 Memory space - * ranges. However, some machines (thanks Apple !) tend to split their - * space into lots of small contiguous ranges. So we have to coalesce. - * - * - We can only cope with all memory ranges having the same offset - * between CPU addresses and PCI addresses. Unfortunately, some bridges - * are setup for a large 1:1 mapping along with a small "window" which - * maps PCI address 0 to some arbitrary high address of the CPU space in - * order to give access to the ISA memory hole. - * The way out of here that I've chosen for now is to always set the - * offset based on the first resource found, then override it if we - * have a different offset and the previous was set by an ISA hole. - * - * - Some busses have IO space not starting at 0, which causes trouble with - * the way we do our IO resource renumbering. The code somewhat deals with - * it for 64 bits but I would expect problems on 32 bits. - * - * - Some 32 bits platforms such as 4xx can have physical space larger than - * 32 bits so we need to use 64 bits values for the parsing - */ -void pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - int memno = 0, isa_hole = -1; - unsigned long long isa_mb = 0; - struct resource *res; - struct of_pci_range range; - struct of_pci_range_parser parser; - - pr_info("PCI host bridge %pOF %s ranges:\n", - dev, primary ? "(primary)" : ""); - - /* Check for ranges property */ - if (of_pci_range_parser_init(&parser, dev)) - return; - - pr_debug("Parsing ranges property...\n"); - for_each_of_pci_range(&parser, &range) { - /* Read next ranges element */ - - /* If we failed translation or got a zero-sized region - * (some FW try to feed us with non sensical zero sized regions - * such as power3 which look like some kind of attempt - * at exposing the VGA memory hole) - */ - if (range.cpu_addr == OF_BAD_ADDR || range.size == 0) - continue; - - /* Act based on address space type */ - res = NULL; - switch (range.flags & IORESOURCE_TYPE_BITS) { - case IORESOURCE_IO: - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", - range.cpu_addr, range.cpu_addr + range.size - 1, - range.pci_addr); - - /* We support only one IO range */ - if (hose->pci_io_size) { - pr_info(" \\--> Skipped (too many) !\n"); - continue; - } - /* On 32 bits, limit I/O space to 16MB */ - if (range.size > 0x01000000) - range.size = 0x01000000; - - /* 32 bits needs to map IOs here */ - hose->io_base_virt = ioremap(range.cpu_addr, - range.size); - - /* Expect trouble if pci_addr is not 0 */ - if (primary) - isa_io_base = - (unsigned long)hose->io_base_virt; - /* pci_io_size and io_base_phys always represent IO - * space starting at 0 so we factor in pci_addr - */ - hose->pci_io_size = range.pci_addr + range.size; - hose->io_base_phys = range.cpu_addr - range.pci_addr; - - /* Build resource */ - res = &hose->io_resource; - range.cpu_addr = range.pci_addr; - - break; - case IORESOURCE_MEM: - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", - range.cpu_addr, range.cpu_addr + range.size - 1, - range.pci_addr, - (range.flags & IORESOURCE_PREFETCH) ? - "Prefetch" : ""); - - /* We support only 3 memory ranges */ - if (memno >= 3) { - pr_info(" \\--> Skipped (too many) !\n"); - continue; - } - /* Handles ISA memory hole space here */ - if (range.pci_addr == 0) { - isa_mb = range.cpu_addr; - isa_hole = memno; - if (primary || isa_mem_base == 0) - isa_mem_base = range.cpu_addr; - hose->isa_mem_phys = range.cpu_addr; - hose->isa_mem_size = range.size; - } - - /* We get the PCI/Mem offset from the first range or - * the, current one if the offset came from an ISA - * hole. If they don't match, bugger. - */ - if (memno == 0 || - (isa_hole >= 0 && range.pci_addr != 0 && - hose->pci_mem_offset == isa_mb)) - hose->pci_mem_offset = range.cpu_addr - - range.pci_addr; - else if (range.pci_addr != 0 && - hose->pci_mem_offset != range.cpu_addr - - range.pci_addr) { - pr_info(" \\--> Skipped (offset mismatch) !\n"); - continue; - } - - /* Build resource */ - res = &hose->mem_resources[memno++]; - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->flags = range.flags; - res->start = range.cpu_addr; - res->end = range.cpu_addr + range.size - 1; - res->parent = res->child = res->sibling = NULL; - } - } - - /* If there's an ISA hole and the pci_mem_offset is -not- matching - * the ISA hole offset, then we need to remove the ISA hole from - * the resource list for that brige - */ - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) { - unsigned int next = isa_hole + 1; - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb); - if (next < memno) - memmove(&hose->mem_resources[isa_hole], - &hose->mem_resources[next], - sizeof(struct resource) * (memno - next)); - hose->mem_resources[--memno].flags = 0; - } -} - -/* Display the domain number in /proc */ -int pci_proc_domain(struct pci_bus *bus) -{ - return pci_domain_nr(bus); -} - -/* This header fixup will do the resource fixup for all devices as they are - * probed, but not for bridge ranges - */ -static void pcibios_fixup_resources(struct pci_dev *dev) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - int i; - - if (!hose) { - pr_err("No host bridge for PCI dev %s !\n", - pci_name(dev)); - return; - } - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = dev->resource + i; - if (!res->flags) - continue; - if (res->start == 0) { - pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]", - pci_name(dev), i, - (unsigned long long)res->start, - (unsigned long long)res->end, - (unsigned int)res->flags); - pr_debug("is unassigned\n"); - res->end -= res->start; - res->start = 0; - res->flags |= IORESOURCE_UNSET; - continue; - } - - pr_debug("PCI:%s Resource %d %016llx-%016llx [%x]\n", - pci_name(dev), i, - (unsigned long long)res->start, - (unsigned long long)res->end, - (unsigned int)res->flags); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); - -int pcibios_device_add(struct pci_dev *dev) -{ - dev->irq = of_irq_parse_and_map_pci(dev, 0, 0); - - return 0; -} - -/* - * Reparent resource children of pr that conflict with res - * under res, and make res replace those children. - */ -static int __init reparent_resources(struct resource *parent, - struct resource *res) -{ - struct resource *p, **pp; - struct resource **firstpp = NULL; - - for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) { - if (p->end < res->start) - continue; - if (res->end < p->start) - break; - if (p->start < res->start || p->end > res->end) - return -1; /* not completely contained */ - if (firstpp == NULL) - firstpp = pp; - } - if (firstpp == NULL) - return -1; /* didn't find any conflicting entries? */ - res->parent = parent; - res->child = *firstpp; - res->sibling = *pp; - *firstpp = res; - *pp = NULL; - for (p = res->child; p != NULL; p = p->sibling) { - p->parent = res; - pr_debug("PCI: Reparented %s [%llx..%llx] under %s\n", - p->name, - (unsigned long long)p->start, - (unsigned long long)p->end, res->name); - } - return 0; -} - -/* - * Handle resources of PCI devices. If the world were perfect, we could - * just allocate all the resource regions and do nothing more. It isn't. - * On the other hand, we cannot just re-allocate all devices, as it would - * require us to know lots of host bridge internals. So we attempt to - * keep as much of the original configuration as possible, but tweak it - * when it's found to be wrong. - * - * Known BIOS problems we have to work around: - * - I/O or memory regions not configured - * - regions configured, but not enabled in the command register - * - bogus I/O addresses above 64K used - * - expansion ROMs left enabled (this may sound harmless, but given - * the fact the PCI specs explicitly allow address decoders to be - * shared between expansion ROMs and other resource regions, it's - * at least dangerous) - * - * Our solution: - * (1) Allocate resources for all buses behind PCI-to-PCI bridges. - * This gives us fixed barriers on where we can allocate. - * (2) Allocate resources for all enabled devices. If there is - * a collision, just mark the resource as unallocated. Also - * disable expansion ROMs during this step. - * (3) Try to allocate resources for disabled devices. If the - * resources were assigned correctly, everything goes well, - * if they weren't, they won't disturb allocation of other - * resources. - * (4) Assign new addresses to resources which were either - * not configured at all or misconfigured. If explicitly - * requested by the user, configure expansion ROM address - * as well. - */ - -static void pcibios_allocate_bus_resources(struct pci_bus *bus) -{ - struct pci_bus *b; - int i; - struct resource *res, *pr; - - pr_debug("PCI: Allocating bus resources for %04x:%02x...\n", - pci_domain_nr(bus), bus->number); - - pci_bus_for_each_resource(bus, res, i) { - if (!res || !res->flags - || res->start > res->end || res->parent) - continue; - if (bus->parent == NULL) - pr = (res->flags & IORESOURCE_IO) ? - &ioport_resource : &iomem_resource; - else { - /* Don't bother with non-root busses when - * re-assigning all resources. We clear the - * resource flags as if they were colliding - * and as such ensure proper re-allocation - * later. - */ - pr = pci_find_parent_resource(bus->self, res); - if (pr == res) { - /* this happens when the generic PCI - * code (wrongly) decides that this - * bridge is transparent -- paulus - */ - continue; - } - } - - pr_debug("PCI: %s (bus %d) bridge rsrc %d: %016llx-%016llx ", - bus->self ? pci_name(bus->self) : "PHB", - bus->number, i, - (unsigned long long)res->start, - (unsigned long long)res->end); - pr_debug("[0x%x], parent %p (%s)\n", - (unsigned int)res->flags, - pr, (pr && pr->name) ? pr->name : "nil"); - - if (pr && !(pr->flags & IORESOURCE_UNSET)) { - struct pci_dev *dev = bus->self; - - if (request_resource(pr, res) == 0) - continue; - /* - * Must be a conflict with an existing entry. - * Move that entry (or entries) under the - * bridge resource and try again. - */ - if (reparent_resources(pr, res) == 0) - continue; - - if (dev && i < PCI_BRIDGE_RESOURCE_NUM && - pci_claim_bridge_resource(dev, - i + PCI_BRIDGE_RESOURCES) == 0) - continue; - - } - pr_warn("PCI: Cannot allocate resource region "); - pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number); - res->start = res->end = 0; - res->flags = 0; - } - - list_for_each_entry(b, &bus->children, node) - pcibios_allocate_bus_resources(b); -} - -static inline void alloc_resource(struct pci_dev *dev, int idx) -{ - struct resource *pr, *r = &dev->resource[idx]; - - pr_debug("PCI: Allocating %s: Resource %d: %016llx..%016llx [%x]\n", - pci_name(dev), idx, - (unsigned long long)r->start, - (unsigned long long)r->end, - (unsigned int)r->flags); - - pr = pci_find_parent_resource(dev, r); - if (!pr || (pr->flags & IORESOURCE_UNSET) || - request_resource(pr, r) < 0) { - pr_warn("PCI: Cannot allocate resource region %d ", idx); - pr_cont("of device %s, will remap\n", pci_name(dev)); - if (pr) - pr_debug("PCI: parent is %p: %016llx-%016llx [%x]\n", - pr, - (unsigned long long)pr->start, - (unsigned long long)pr->end, - (unsigned int)pr->flags); - /* We'll assign a new address later */ - r->flags |= IORESOURCE_UNSET; - r->end -= r->start; - r->start = 0; - } -} - -static void __init pcibios_allocate_resources(int pass) -{ - struct pci_dev *dev = NULL; - int idx, disabled; - u16 command; - struct resource *r; - - for_each_pci_dev(dev) { - pci_read_config_word(dev, PCI_COMMAND, &command); - for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { - r = &dev->resource[idx]; - if (r->parent) /* Already allocated */ - continue; - if (!r->flags || (r->flags & IORESOURCE_UNSET)) - continue; /* Not assigned at all */ - /* We only allocate ROMs on pass 1 just in case they - * have been screwed up by firmware - */ - if (idx == PCI_ROM_RESOURCE) - disabled = 1; - if (r->flags & IORESOURCE_IO) - disabled = !(command & PCI_COMMAND_IO); - else - disabled = !(command & PCI_COMMAND_MEMORY); - if (pass == disabled) - alloc_resource(dev, idx); - } - if (pass) - continue; - r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags) { - /* Turn the ROM off, leave the resource region, - * but keep it unregistered. - */ - u32 reg; - pci_read_config_dword(dev, dev->rom_base_reg, ®); - if (reg & PCI_ROM_ADDRESS_ENABLE) { - pr_debug("PCI: Switching off ROM of %s\n", - pci_name(dev)); - r->flags &= ~IORESOURCE_ROM_ENABLE; - pci_write_config_dword(dev, dev->rom_base_reg, - reg & ~PCI_ROM_ADDRESS_ENABLE); - } - } - } -} - -static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus) -{ - struct pci_controller *hose = pci_bus_to_host(bus); - resource_size_t offset; - struct resource *res, *pres; - int i; - - pr_debug("Reserving legacy ranges for domain %04x\n", - pci_domain_nr(bus)); - - /* Check for IO */ - if (!(hose->io_resource.flags & IORESOURCE_IO)) - goto no_io; - offset = (unsigned long)hose->io_base_virt - _IO_BASE; - res = kzalloc(sizeof(struct resource), GFP_KERNEL); - BUG_ON(res == NULL); - res->name = "Legacy IO"; - res->flags = IORESOURCE_IO; - res->start = offset; - res->end = (offset + 0xfff) & 0xfffffffful; - pr_debug("Candidate legacy IO: %pR\n", res); - if (request_resource(&hose->io_resource, res)) { - pr_debug("PCI %04x:%02x Cannot reserve Legacy IO %pR\n", - pci_domain_nr(bus), bus->number, res); - kfree(res); - } - - no_io: - /* Check for memory */ - offset = hose->pci_mem_offset; - pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset); - for (i = 0; i < 3; i++) { - pres = &hose->mem_resources[i]; - if (!(pres->flags & IORESOURCE_MEM)) - continue; - pr_debug("hose mem res: %pR\n", pres); - if ((pres->start - offset) <= 0xa0000 && - (pres->end - offset) >= 0xbffff) - break; - } - if (i >= 3) - return; - res = kzalloc(sizeof(struct resource), GFP_KERNEL); - BUG_ON(res == NULL); - res->name = "Legacy VGA memory"; - res->flags = IORESOURCE_MEM; - res->start = 0xa0000 + offset; - res->end = 0xbffff + offset; - pr_debug("Candidate VGA memory: %pR\n", res); - if (request_resource(pres, res)) { - pr_debug("PCI %04x:%02x Cannot reserve VGA memory %pR\n", - pci_domain_nr(bus), bus->number, res); - kfree(res); - } -} - -void __init pcibios_resource_survey(void) -{ - struct pci_bus *b; - - /* Allocate and assign resources. If we re-assign everything, then - * we skip the allocate phase - */ - list_for_each_entry(b, &pci_root_buses, node) - pcibios_allocate_bus_resources(b); - - pcibios_allocate_resources(0); - pcibios_allocate_resources(1); - - /* Before we start assigning unassigned resource, we try to reserve - * the low IO area and the VGA memory area if they intersect the - * bus available resources to avoid allocating things on top of them - */ - list_for_each_entry(b, &pci_root_buses, node) - pcibios_reserve_legacy_regions(b); - - /* Now proceed to assigning things that were left unassigned */ - pr_debug("PCI: Assigning unassigned resources...\n"); - pci_assign_unassigned_resources(); -} - -static void pcibios_setup_phb_resources(struct pci_controller *hose, - struct list_head *resources) -{ - unsigned long io_offset; - struct resource *res; - int i; - - /* Hookup PHB IO resource */ - res = &hose->io_resource; - - /* Fixup IO space offset */ - io_offset = (unsigned long)hose->io_base_virt - isa_io_base; - res->start = (res->start + io_offset) & 0xffffffffu; - res->end = (res->end + io_offset) & 0xffffffffu; - - if (!res->flags) { - pr_warn("PCI: I/O resource not set for host "); - pr_cont("bridge %pOF (domain %d)\n", - hose->dn, hose->global_number); - /* Workaround for lack of IO resource only on 32-bit */ - res->start = (unsigned long)hose->io_base_virt - isa_io_base; - res->end = res->start + IO_SPACE_LIMIT; - res->flags = IORESOURCE_IO; - } - pci_add_resource_offset(resources, res, - (__force resource_size_t)(hose->io_base_virt - _IO_BASE)); - - pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n", - (unsigned long long)res->start, - (unsigned long long)res->end, - (unsigned long)res->flags); - - /* Hookup PHB Memory resources */ - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (!res->flags) { - if (i > 0) - continue; - pr_err("PCI: Memory resource 0 not set for "); - pr_cont("host bridge %pOF (domain %d)\n", - hose->dn, hose->global_number); - - /* Workaround for lack of MEM resource only on 32-bit */ - res->start = hose->pci_mem_offset; - res->end = (resource_size_t)-1LL; - res->flags = IORESOURCE_MEM; - - } - pci_add_resource_offset(resources, res, hose->pci_mem_offset); - - pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", - i, (unsigned long long)res->start, - (unsigned long long)res->end, - (unsigned long)res->flags); - } - - pr_debug("PCI: PHB MEM offset = %016llx\n", - (unsigned long long)hose->pci_mem_offset); - pr_debug("PCI: PHB IO offset = %08lx\n", - (unsigned long)hose->io_base_virt - _IO_BASE); -} - -static void pcibios_scan_phb(struct pci_controller *hose) -{ - LIST_HEAD(resources); - struct pci_bus *bus; - struct device_node *node = hose->dn; - - pr_debug("PCI: Scanning PHB %pOF\n", node); - - pcibios_setup_phb_resources(hose, &resources); - - bus = pci_scan_root_bus(hose->parent, hose->first_busno, - hose->ops, hose, &resources); - if (bus == NULL) { - pr_err("Failed to create bus for PCI domain %04x\n", - hose->global_number); - pci_free_resource_list(&resources); - return; - } - bus->busn_res.start = hose->first_busno; - hose->bus = bus; - - hose->last_busno = bus->busn_res.end; -} - -static int __init pcibios_init(void) -{ - struct pci_controller *hose, *tmp; - int next_busno = 0; - - pr_info("PCI: Probing PCI hardware\n"); - - /* Scan all of the recorded PCI controllers. */ - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - hose->last_busno = 0xff; - pcibios_scan_phb(hose); - if (next_busno <= hose->last_busno) - next_busno = hose->last_busno + 1; - } - pci_bus_count = next_busno; - - /* Call common code to handle resource allocation */ - pcibios_resource_survey(); - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { - if (hose->bus) - pci_bus_add_devices(hose->bus); - } - - return 0; -} - -subsys_initcall(pcibios_init); - -static struct pci_controller *pci_bus_to_hose(int bus) -{ - struct pci_controller *hose, *tmp; - - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) - if (bus >= hose->first_busno && bus <= hose->last_busno) - return hose; - return NULL; -} - -/* Provide information on locations of various I/O regions in physical - * memory. Do this on a per-card basis so that we choose the right - * root bridge. - * Note that the returned IO or memory base is a physical address - */ - -long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) -{ - struct pci_controller *hose; - long result = -EOPNOTSUPP; - - hose = pci_bus_to_hose(bus); - if (!hose) - return -ENODEV; - - switch (which) { - case IOBASE_BRIDGE_NUMBER: - return (long)hose->first_busno; - case IOBASE_MEMORY: - return (long)hose->pci_mem_offset; - case IOBASE_IO: - return (long)hose->io_base_phys; - case IOBASE_ISA_IO: - return (long)isa_io_base; - case IOBASE_ISA_MEM: - return (long)isa_mem_base; - } - - return result; -} - -/* - * Null PCI config access functions, for the case when we can't - * find a hose. - */ -#define NULL_PCI_OP(rw, size, type) \ -static int \ -null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - return PCIBIOS_DEVICE_NOT_FOUND; \ -} - -static int -null_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static int -null_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static struct pci_ops null_pci_ops = { - .read = null_read_config, - .write = null_write_config, -}; - -/* - * These functions are used early on before PCI scanning is done - * and all of the pci_dev and pci_bus structures have been created. - */ -static struct pci_bus * -fake_pci_bus(struct pci_controller *hose, int busnr) -{ - static struct pci_bus bus; - - if (!hose) - pr_err("Can't find hose for PCI bus %d!\n", busnr); - - bus.number = busnr; - bus.sysdata = hose; - bus.ops = hose ? hose->ops : &null_pci_ops; - return &bus; -} - -#define EARLY_PCI_OP(rw, size, type) \ -int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ - int devfn, int offset, type value) \ -{ \ - return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus), \ - devfn, offset, value); \ -} - -EARLY_PCI_OP(read, byte, u8 *) -EARLY_PCI_OP(read, word, u16 *) -EARLY_PCI_OP(read, dword, u32 *) -EARLY_PCI_OP(write, byte, u8) -EARLY_PCI_OP(write, word, u16) -EARLY_PCI_OP(write, dword, u32) - -int early_find_capability(struct pci_controller *hose, int bus, int devfn, - int cap) -{ - return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap); -} diff --git a/arch/microblaze/pci/xilinx_pci.c b/arch/microblaze/pci/xilinx_pci.c deleted file mode 100644 index f4cb86fffcee..000000000000 --- a/arch/microblaze/pci/xilinx_pci.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * PCI support for Xilinx plbv46_pci soft-core which can be used on - * Xilinx Virtex ML410 / ML510 boards. - * - * Copyright 2009 Roderick Colenbrander - * Copyright 2009 Secret Lab Technologies Ltd. - * - * The pci bridge fixup code was copied from ppc4xx_pci.c and was written - * by Benjamin Herrenschmidt. - * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include <linux/ioport.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/pci.h> -#include <linux/io.h> - -#define XPLB_PCI_ADDR 0x10c -#define XPLB_PCI_DATA 0x110 -#define XPLB_PCI_BUS 0x114 - -#define PCI_HOST_ENABLE_CMD (PCI_COMMAND_SERR | PCI_COMMAND_PARITY | \ - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY) - -static const struct of_device_id xilinx_pci_match[] = { - { .compatible = "xlnx,plbv46-pci-1.03.a", }, - {} -}; - -/** - * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration. - */ -static void xilinx_pci_fixup_bridge(struct pci_dev *dev) -{ - struct pci_controller *hose; - int i; - - if (dev->devfn || dev->bus->self) - return; - - hose = pci_bus_to_host(dev->bus); - if (!hose) - return; - - if (!of_match_node(xilinx_pci_match, hose->dn)) - return; - - /* Hide the PCI host BARs from the kernel as their content doesn't - * fit well in the resource management - */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - dev->resource[i].start = 0; - dev->resource[i].end = 0; - dev->resource[i].flags = 0; - } - - dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n", - pci_name(dev)); -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge); - -#ifdef DEBUG -/** - * xilinx_pci_exclude_device - Don't do config access for non-root bus - * - * This is a hack. Config access to any bus other than bus 0 does not - * currently work on the ML510 so we prevent it here. - */ -static int -xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn) -{ - return (bus != 0); -} - -/** - * xilinx_early_pci_scan - List pci config space for available devices - * - * List pci devices in very early phase. - */ -static void __init xilinx_early_pci_scan(struct pci_controller *hose) -{ - u32 bus = 0; - u32 val, dev, func, offset; - - /* Currently we have only 2 device connected - up-to 32 devices */ - for (dev = 0; dev < 2; dev++) { - /* List only first function number - up-to 8 functions */ - for (func = 0; func < 1; func++) { - pr_info("%02x:%02x:%02x", bus, dev, func); - /* read the first 64 standardized bytes */ - /* Up-to 192 bytes can be list of capabilities */ - for (offset = 0; offset < 64; offset += 4) { - early_read_config_dword(hose, bus, - PCI_DEVFN(dev, func), offset, &val); - if (offset == 0 && val == 0xFFFFFFFF) { - pr_cont("\nABSENT"); - break; - } - if (!(offset % 0x10)) - pr_cont("\n%04x: ", offset); - - pr_cont("%08x ", val); - } - pr_info("\n"); - } - } -} -#else -static void __init xilinx_early_pci_scan(struct pci_controller *hose) -{ -} -#endif - -/** - * xilinx_pci_init - Find and register a Xilinx PCI host bridge - */ -void __init xilinx_pci_init(void) -{ - struct pci_controller *hose; - struct resource r; - void __iomem *pci_reg; - struct device_node *pci_node; - - pci_node = of_find_matching_node(NULL, xilinx_pci_match); - if (!pci_node) - return; - - if (of_address_to_resource(pci_node, 0, &r)) { - pr_err("xilinx-pci: cannot resolve base address\n"); - return; - } - - hose = pcibios_alloc_controller(pci_node); - if (!hose) { - pr_err("xilinx-pci: pcibios_alloc_controller() failed\n"); - return; - } - - /* Setup config space */ - setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR, - r.start + XPLB_PCI_DATA, - INDIRECT_TYPE_SET_CFG_TYPE); - - /* According to the xilinx plbv46_pci documentation the soft-core starts - * a self-init when the bus master enable bit is set. Without this bit - * set the pci bus can't be scanned. - */ - early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD); - - /* Set the max latency timer to 255 */ - early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff); - - /* Set the max bus number to 255, and bus/subbus no's to 0 */ - pci_reg = of_iomap(pci_node, 0); - WARN_ON(!pci_reg); - out_be32(pci_reg + XPLB_PCI_BUS, 0x000000ff); - iounmap(pci_reg); - - /* Register the host bridge with the linux kernel! */ - pci_process_bridge_OF_ranges(hose, pci_node, - INDIRECT_TYPE_SET_CFG_TYPE); - - pr_info("xilinx-pci: Registered PCI host bridge\n"); - xilinx_early_pci_scan(hose); -} |