diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-12 09:37:09 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-12 09:37:09 -0800 |
| commit | 164f59000c19fa1ee5d09327a8055ec9f9b9905a (patch) | |
| tree | c613bd29f5489ebbd85a767fe789332983976d66 /arch | |
| parent | 7d62159919c90fbcd9ee808e9f1b776eae990d53 (diff) | |
| parent | 5cfe469c2654c3a4dda8504b1209abdd8b379e95 (diff) | |
| download | linux-164f59000c19fa1ee5d09327a8055ec9f9b9905a.tar.gz linux-164f59000c19fa1ee5d09327a8055ec9f9b9905a.tar.bz2 linux-164f59000c19fa1ee5d09327a8055ec9f9b9905a.zip | |
Merge tag 'microblaze-v6.2' of git://git.monstr.eu/linux-2.6-microblaze
Pull microblaze updates from Michal Simek:
"Clean up PCI support which was pretty much copied and pasted from
PowerPC long time ago for one custom platform which is not available
for years.
Also, the Xilinx/AMD PCIe team tested Microblaze with IP cores also
used on ARM SOCs and clean up Microblaze code"
* tag 'microblaze-v6.2' of git://git.monstr.eu/linux-2.6-microblaze:
microblaze/PCI: Moving PCI iounmap and dependent code
microblaze/PCI: Remove support for Xilinx PCI host bridge
microblaze/PCI: Remove unused pci_iobar_pfn() and et al declarations
microblaze/PCI: Remove unused sys_pciconfig_iobase() and et al declaration
microblaze/PCI: Remove unused pci_address_to_pio() conversion of CPU address to I/O port
microblaze/PCI: Remove unused PCI Indirect ops
microblaze/PCI: Remove unused PCI BIOS resource allocation
microblaze/PCI: Remove unused allocation & free of PCI host bridge structure
microblaze/PCI: Remove unused device tree parsing for a host bridge resources
microblaze/PCI: Remove unused PCI legacy IO's access on a bus
microblaze/PCI: Remove unused PCI bus scan if configured as a host
microblaze/PCI: Remove Null PCI config access unused functions
microblaze/PCI: Remove unused early_read_config_byte() et al declarations
Diffstat (limited to 'arch')
| -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/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 |
9 files changed, 37 insertions, 1527 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/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); < |
