PCI: Fixup for 64bit resource with sparc
Subsystems (11)
v12 cover PCI: Fixup for 64bit resource with sparc
Hi Bjorn,
After 5b28541552ef (PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources), we have several reports on resource allocation failure, and we try to fix the problem with resource clip, and find more problems.
One is from sparc that have problem with clip as we don't parse mem64 for it.
This patchset try to fix the problem for sparc.
patch 1-2: try to fix the pci mmap for proc path for sparc, that will make fix for sparc 64bit resource offset handling much simple.
patch 3-10: parse MEM64 for sparc and other system with OF. So device 64bit resource could find their parent resource.
patch 11-14: MMIO64 handling enhancement
treat non-pref mmio64 if parent bridges are all pcie.
patch 15: restore old pref allocation logic if hostbridge does not support mmio64.
Khalid Aziz tested on some sparc platforms that have different offset to mem space start or support 64bit mmio.
-v12: add two pci_mmap_page_range() related patches, and
only include sparc related patches at first. will submit other later.
Hope we can get them into v4.8.
Thanks
Yinghai
Yinghai Lu (15):
PCI: Let pci_mmap_page_range() take extra resource pointer
PCI: Let pci_mmap_page_range() take resource address sparc/PCI: Use correct offset for bus address to resource
PCI: Add pci_find_bus_resource()
sparc/PCI: Reserve legacy mmio after PCI mmio
sparc/PCI: Add IORESOURCE_MEM_64 for 64-bit resource in OF parsing sparc/PCI: Keep resource idx order with bridge register number powerpc/PCI: Keep resource idx order with bridge register number powerpc/PCI: Add IORESOURCE_MEM_64 for 64-bit resource in OF parsing OF/PCI: Add IORESOURCE_MEM_64 for 64-bit resource
PCI: Check pref compatible bit for mem64 resource of PCIe device
PCI: Only treat non-pref mmio64 as pref if all bridges have MEM_64
PCI: Add has_mem64 for struct host_bridge
PCI: Only treat non-pref mmio64 as pref if host bridge has mmio64
PCI: Restore pref MMIO allocation logic for host bridge without mmio64
arch/arm/include/asm/pci.h | 2 - arch/arm/kernel/bios32.c | 3 +- arch/cris/arch-v32/drivers/pci/bios.c | 3 +- arch/cris/include/asm/pci.h | 3 - arch/ia64/include/asm/pci.h | 2 - arch/ia64/pci/pci.c | 3 +- arch/microblaze/include/asm/pci.h | 3 - arch/microblaze/pci/pci-common.c | 81 +++--------------- arch/mips/include/asm/pci.h | 3 - arch/mips/pci/pci.c | 3 +- arch/mn10300/include/asm/pci.h | 3 - arch/mn10300/unit-asb2305/pci-asb2305.c | 3 +- arch/parisc/include/asm/pci.h | 3 - arch/parisc/kernel/pci.c | 3 +- arch/powerpc/include/asm/pci.h | 3 - arch/powerpc/kernel/pci-common.c | 81 +++--------------- arch/powerpc/kernel/pci_of_scan.c | 12 ++- arch/sh/drivers/pci/pci.c | 3 +- arch/sh/include/asm/pci.h | 2 - arch/sparc/include/asm/pci_64.h | 4 - arch/sparc/kernel/of_device_32.c | 5 +- arch/sparc/kernel/of_device_64.c | 5 +- arch/sparc/kernel/pci.c | 147 ++++---------------------------- arch/sparc/kernel/pci_common.c | 91 ++++++++++++-------- arch/sparc/kernel/pci_impl.h | 5 ++ arch/unicore32/include/asm/pci.h | 2 - arch/unicore32/kernel/pci.c | 3 +- arch/x86/include/asm/pci.h | 4 - arch/x86/pci/i386.c | 3 +- arch/xtensa/include/asm/pci.h | 4 - arch/xtensa/kernel/pci.c | 78 +++-------------- drivers/of/address.c | 4 +- drivers/pci/bus.c | 4 +- drivers/pci/pci-sysfs.c | 35 +++++--- drivers/pci/pci.c | 31 ++++--- drivers/pci/pci.h | 4 +- drivers/pci/probe.c | 40 +++++++++ drivers/pci/proc.c | 65 +++++++++++--- drivers/pci/setup-bus.c | 65 ++++++++++++-- drivers/pci/setup-res.c | 13 ++- include/linux/pci.h | 10 +++ 41 files changed, 367 insertions(+), 474 deletions(-)
Signature · 1 line
2.8.3
PATCH v12 1/15 PCI: Let pci_mmap_page_range() take extra resource pointer
This one is preparing patch for next one:
PCI: Let pci_mmap_page_range() take resource addr
We need to pass extra resource pointer to avoid searching that again for powerpc and microblaze prot set operation.
--- arch/arm/include/asm/pci.h | 2 -- arch/arm/kernel/bios32.c | 3 ++- arch/cris/arch-v32/drivers/pci/bios.c | 3 ++- arch/cris/include/asm/pci.h | 3 --- arch/ia64/include/asm/pci.h | 2 -- arch/ia64/pci/pci.c | 3 ++- arch/microblaze/include/asm/pci.h | 3 --- arch/microblaze/pci/pci-common.c | 3 ++- arch/mips/include/asm/pci.h | 3 --- arch/mips/pci/pci.c | 3 ++- arch/mn10300/include/asm/pci.h | 3 --- arch/mn10300/unit-asb2305/pci-asb2305.c | 3 ++- arch/parisc/include/asm/pci.h | 3 --- arch/parisc/kernel/pci.c | 3 ++- arch/powerpc/include/asm/pci.h | 3 --- arch/powerpc/kernel/pci-common.c | 3 ++- arch/sh/drivers/pci/pci.c | 3 ++- arch/sh/include/asm/pci.h | 2 -- arch/sparc/include/asm/pci_64.h | 4 ---- arch/sparc/kernel/pci.c | 3 ++- arch/unicore32/include/asm/pci.h | 2 -- arch/unicore32/kernel/pci.c | 3 ++- arch/x86/include/asm/pci.h | 4 ---- arch/x86/pci/i386.c | 3 ++- arch/xtensa/include/asm/pci.h | 4 ---- arch/xtensa/kernel/pci.c | 3 ++- drivers/pci/pci-sysfs.c | 2 +- drivers/pci/pci.h | 2 +- drivers/pci/proc.c | 2 +- include/linux/pci.h | 6 ++++++ 30 files changed, 35 insertions(+), 54 deletions(-)
arch/arm/include/asm/pci.h +0 -2
@@ -29,8 +29,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)#define PCI_DMA_BUS_IS_PHYS (1)#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);static inline int pci_get_legacy_ide_irq (struct pci_dev *dev,int channel) {
arch/arm/kernel/bios32.c +2 -1
@@ -602,7 +602,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)return pci_enable_resources (dev, mask); } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {if (mmap_state == pci_mmap_io)
arch/cris/arch-v32/drivers/pci/bios.c +2 -1
@@ -14,7 +14,8 @@ void pcibios_set_master(struct pci_dev *dev)pci_write_config_byte (dev,PCI_LATENCY_TIMER , lat); } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;
arch/cris/include/asm/pci.h +0 -3
@@ -42,9 +42,6 @@ struct pci_dev;#define PCI_DMA_BUS_IS_PHYS (1)#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine); -#endif /* __KERNEL__ */
arch/ia64/include/asm/pci.h +0 -2
@@ -51,8 +51,6 @@ extern unsigned long ia64_max_iommu_merge_mask;#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL)#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);#define HAVE_PCI_LEGACY extern int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
arch/ia64/pci/pci.c +2 -1
@@ -419,7 +419,8 @@ pcibios_align_resource (void *data, const struct resource *res, }int -pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long size = vma->vm_end - vma->vm_start;
arch/microblaze/include/asm/pci.h +0 -3
@@ -46,9 +46,6 @@ extern int pci_domain_nr(struct pci_bus *bus);extern int pci_proc_domain (struct pci_bus *bus);struct vm_area_struct ; -/* Map a range of PCI memory or I/O space for a device into user space */ -int pci_mmap_page_range (struct pci_dev *pdev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */ #define HAVE_PCI_MMAP 1
arch/microblaze/pci/pci-common.c +2 -1
@@ -304,7 +304,8 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,* * Returns a negative error code on failure, zero on success. */ -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *rp, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) { resource_size_t offset =
arch/mips/include/asm/pci.h +0 -3
@@ -75,9 +75,6 @@ extern void pcibios_set_master(struct pci_dev *dev);#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine); -#define HAVE_ARCH_PCI_RESOURCE_TO_USER static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
arch/mips/pci/pci.c +2 -1
@@ -319,7 +319,8 @@ void pcibios_fixup_bus(struct pci_bus *bus)EXPORT_SYMBOL (PCIBIOS_MIN_IO );EXPORT_SYMBOL (PCIBIOS_MIN_MEM ); -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;
arch/mn10300/include/asm/pci.h +0 -3
@@ -74,9 +74,6 @@ static inline int pci_controller_num(struct pci_dev *dev) }#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state, -int write_combine);#endif /* __KERNEL__ */
arch/mn10300/unit-asb2305/pci-asb2305.c +2 -1
@@ -211,7 +211,8 @@ void __init pcibios_resource_survey(void)pcibios_allocate_resources (1 ); } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;
arch/parisc/include/asm/pci.h +0 -3
@@ -201,7 +201,4 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine); -#endif /* __ASM_PARISC_PCI_H */
arch/parisc/kernel/pci.c +2 -1
@@ -228,7 +228,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;
arch/powerpc/include/asm/pci.h +0 -3
@@ -77,9 +77,6 @@ extern int pci_domain_nr(struct pci_bus *bus);extern int pci_proc_domain (struct pci_bus *bus);struct vm_area_struct ; -/* Map a range of PCI memory or I/O space for a device into user space */ -int pci_mmap_page_range (struct pci_dev *pdev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */ #define HAVE_PCI_MMAP 1
arch/powerpc/kernel/pci-common.c +2 -1
@@ -445,7 +445,8 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,* * Returns a negative error code on failure, zero on success. */ -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *rp, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) { resource_size_t offset =
arch/sh/drivers/pci/pci.c +2 -1
@@ -269,7 +269,8 @@ void __init_refok pcibios_report_status(unsigned int status_mask, int warn) } } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {/*
arch/sh/include/asm/pci.h +0 -2
@@ -66,8 +66,6 @@ extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;struct pci_dev ;#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);extern void pcibios_set_master (struct pci_dev *dev);/* Dynamic DMA mapping stuff.
arch/sparc/include/asm/pci_64.h +0 -4
@@ -45,10 +45,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA #define get_pci_unmapped_area get_fb_unmapped_area -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state, -int write_combine); -static inline int pci_get_legacy_ide_irq (struct pci_dev *dev,int channel) {return PCI_IRQ_NONE ;
arch/sparc/kernel/pci.c +2 -1
@@ -862,7 +862,8 @@ static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vm* * Returns a negative error code on failure, zero on success. */ -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {
arch/unicore32/include/asm/pci.h +0 -2
@@ -17,8 +17,6 @@#include <mach/hardware.h> /* for PCIBIOS_MIN_* */ #define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine);#endif /* __KERNEL__ */ #endif
arch/unicore32/kernel/pci.c +2 -1
@@ -362,7 +362,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)return 0 ; } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long phys;
arch/x86/include/asm/pci.h +0 -4
@@ -88,10 +88,6 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state, -int write_combine); -#ifdef CONFIG_PCI extern void early_quirks (void );
arch/x86/pci/i386.c +2 -1
@@ -411,7 +411,8 @@ static const struct vm_operations_struct pci_mmap_ops = { .access = generic_access_phys, }; -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;
arch/xtensa/include/asm/pci.h +0 -4
@@ -46,10 +46,6 @@ struct pci_dev;#define PCI_DMA_BUS_IS_PHYS (1) -/* Map a range of PCI memory or I/O space for a device into user space */ -int pci_mmap_page_range (struct pci_dev *pdev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine); -/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */ #define HAVE_PCI_MMAP 1
arch/xtensa/kernel/pci.c +2 -1
@@ -362,7 +362,8 @@ __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,* * Returns a negative error code on failure, zero on success. */ -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {
drivers/pci/pci-sysfs.c +1 -1
@@ -1027,7 +1027,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,pci_resource_to_user (pdev, i, res, &start, &end); vma->vm_pgoff += start >>PAGE_SHIFT ; mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; -return pci_mmap_page_range (pdev, vma, mmap_type, write_combine); +return pci_mmap_page_range (pdev, res, vma, mmap_type, write_combine); } static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
drivers/pci/pci.h +1 -1
@@ -30,7 +30,7 @@ enum pci_mmap_api {PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */ };int pci_mmap_fits (struct pci_dev *pdev,int resno,struct vm_area_struct *vmai, -enum pci_mmap_api mmap_api); +enum pci_mmap_state mmap_type,enum pci_mmap_api mmap_api);#endif int pci_probe_reset_function (struct pci_dev *dev);
drivers/pci/proc.c +1 -1
@@ -245,7 +245,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)if (i >=PCI_ROM_RESOURCE )return -ENODEV ; - ret =pci_mmap_page_range (dev, vma, + ret =pci_mmap_page_range (dev, &dev->resource[i], vma, fpriv->mmap_state, fpriv->write_combine);if (ret <0 )
include/linux/pci.h +6 -0
@@ -70,6 +70,12 @@ enum pci_mmap_state { pci_mmap_mem }; +struct vm_area_struct ; +/* Map a range of PCI memory or I/O space for a device into user space */ +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma, +enum pci_mmap_state mmap_state,int write_combine); +/* * For PCI devices, the region numbers are assigned this way: */
Signature · 1 line
2.8.3
Re: [PATCH v12 01/15] PCI: Let pci_mmap_page_range() take extra resource pointer
Quoted 8 lines · Yinghai Lu
This one is preparing patch for next one:
PCI: Letpci_mmap_page_range()take resource addrWe need to pass extra resource pointer to avoid searching that again for powerpc and microblaze prot set operation.
Signed-off-by Yinghai Lu <[email protected]>Cc linux-arm-kernel at lists.infradead.org
For the CRIS part:
Quoted 19 lines
arch/cris/arch-v32/drivers/pci/bios.c +2
-1@@ -14,7 +14,8 @@ void pcibios_set_master(struct pci_dev *dev)pci_write_config_byte (dev,PCI_LATENCY_TIMER , lat); } -int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma,enum pci_mmap_state mmap_state,int write_combine) {unsigned long prot;arch/cris/include/asm/pci.h +0
-0
arch/cris/include/asm/pci.h struct pci_dev; · line 46
Quoted 8 lines
arch/cris/include/asm/pci.h +0
-3@@ -42,9 +42,6 @@ struct pci_dev;#define PCI_DMA_BUS_IS_PHYS (1)#define HAVE_PCI_MMAP -extern int pci_mmap_page_range (struct pci_dev *dev,struct vm_area_struct *vma, -enum pci_mmap_state mmap_state,int write_combine); -#endif /* __KERNEL__ */
/^JN - Jesper Nilsson
Signature · 1 line
Jesper Nilsson -- jesper.nilsson at axis.com
Re: [PATCH v12 01/15] PCI: Let pci_mmap_page_range() take extra resource pointer
In reply to Yinghai LuQuoted 5 lines · Yinghai Lu
This one is preparing patch for next one:
PCI: Letpci_mmap_page_range()take resource addrWe need to pass extra resource pointer to avoid searching that again for powerpc and microblaze prot set operation.
I'm not convinced yet that the extra resource pointer is necessary.
Microblaze does look up the resource in pci_mmap_page_range(), but it never actually uses it. It *looks* like it uses it, but that code is actually dead and I think we should apply the first patch below.
That leaves powerpc as the only arch that would use this extra resource pointer. It uses it in __pci_mmap_set_pgprot() to help decide whether to make a normal uncacheable mapping or a write- combining one. There's nothing here that's specific to the powerpc architecture, and I don't think we should add this parameter just to cater to powerpc.
There are two cases where __pci_mmap_set_pgprot() on powerpc does something based on the resource:
1) We're using procfs to mmap I/O port space after we requested write-combining, e.g., we did this:
ioctl(fd, PCIIOC_MMAP_IS_IO); # request I/O port space
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
mmap(fd, ...)
On powerpc, we ignore the write-combining request in this case.
I think we can handle this case by applying the second patch below to ignore write-combining on I/O space for all arches, not just powerpc.
2) We're using sysfs to mmap resourceN (not resourceN_wc), and the resource is prefetchable. On powerpc, we turn *on* write-combining, even though the user didn't ask for it.
I'm not sure this case is actually safe, because it changes the ordering properties. If it *is* safe, we could enable write- combining in pci_mmap_resource(), where we already have the resource and it could be done for all arches.
This case is not strictly necessary, except to avoid a performance regression, because the user could have mapped resourceN_wc to explicitly request write-combining.
Quoted 33 lines
drivers/pci/pci-sysfs.c +1
-1@@ -1027,7 +1027,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,pci_resource_to_user (pdev, i, res, &start, &end); vma->vm_pgoff += start >>PAGE_SHIFT ; mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; -return pci_mmap_page_range (pdev, vma, mmap_type, write_combine); +return pci_mmap_page_range (pdev, res, vma, mmap_type, write_combine); } static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,drivers/pci/proc.c +1
-1@@ -245,7 +245,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)if (i >=PCI_ROM_RESOURCE )return -ENODEV ; - ret =pci_mmap_page_range (dev, vma, + ret =pci_mmap_page_range (dev, &dev->resource[i], vma, fpriv->mmap_state, fpriv->write_combine);if (ret <0 )include/linux/pci.h +0
-0@@ -70,6 +70,12 @@ enum pci_mmap_state { pci_mmap_mem };
include/linux/pci.h enum pci_mmap_state { · line 81
Quoted 10 lines
include/linux/pci.h +6
-0+struct vm_area_struct ; +/* Map a range of PCI memory or I/O space for a device into user space */ +int pci_mmap_page_range (struct pci_dev *dev,struct resource *res, +struct vm_area_struct *vma, +enum pci_mmap_state mmap_state,int write_combine); +/* * For PCI devices, the region numbers are assigned this way: */
commit 4e712b691abc5b579e3e4327f56b0b7988bdd1cb
Author: Bjorn Helgaas <[email protected]> Date: Wed Jun 8 14:00:14 2016 -0500
microblaze/PCI: Remove useless __pci_mmap_set_pgprot()
The microblaze __pci_mmap_set_pgprot() was apparently copied from powerpc, where it computes either an uncacheable pgprot_t or a write-combining one. But on microblaze, we always use the regular uncacheable pgprot_t.
Remove the useless code in __pci_mmap_set_pgprot() and inline the pgprot_noncached() at the only caller.
arch/microblaze/pci/pci-common.c +1 -30
@@ -219,33 +219,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, }/* -* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci -* device mapping. -*/ -static pgprot_t __pci_mmap_set_pgprot (struct pci_dev *dev,struct resource *rp, -pgprot_t protection, -enum pci_mmap_state mmap_state, -int write_combine) -{ -pgprot_t prot = protection; - -/* Write combine is always 0 on non-memory space mappings. On -* memory space, if the user didn't pass 1, we check for a -* "prefetchable" resource. This is a bit hackish, but we use -* this to workaround the inability of /sysfs to provide a write -* combine bit -*/ -if (mmap_state != pci_mmap_mem) - write_combine =0 ; -else if (write_combine ==0 ) { -if (rp->flags &IORESOURCE_PREFETCH ) - write_combine =1 ; - } - -return pgprot_noncached (prot); -} - -/* * This one is used by /dev/mem and fbdev who have no clue about the * PCI device, it tries to find the PCI device first and calls the * above routine
@@ -317,9 +290,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,return -EINVAL ; vma->vm_pgoff = offset >>PAGE_SHIFT ; - vma->vm_page_prot =__pci_mmap_set_pgprot (dev, rp, - vma->vm_page_prot, - mmap_state, write_combine); + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot); ret =remap_pfn_range (vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot);
commit 962972ee5e0ba6ceb680cb182bad65f8886586a6
Author: Bjorn Helgaas <[email protected]> Date: Wed Jun 8 14:46:54 2016 -0500
PCI: Ignore write-combining when mapping I/O port space
PCI exposes files like /proc/bus/pci/00/00.0 in procfs. These files support operations like this:
ioctl(fd, PCIIOC_MMAP_IS_IO); # request I/O port space
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
mmap(fd, ...)
Many architectures don't allow mmap of I/O port space at all, but I don't think it makes sense to do a write-combining mapping on the ones that do. We could change proc_bus_pci_ioctl() so the user could never enable write- combining for I/O port space, but that would break the following sequence, which is currently legal:
mmap(fd, ...) # default is I/O, non-combining
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
ioctl(fd, PCIIOC_MMAP_IS_MEM); # request memory space
mmap(fd, ...)
Ignore the write-combining flag when mapping I/O port space.
drivers/pci/proc.c +2 -1
@@ -247,7 +247,8 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) ret =pci_mmap_page_range (dev, vma, fpriv->mmap_state, - fpriv->write_combine); + (fpriv->mmap_state == pci_mmap_mem) ? + fpriv->write_combine :0 );if (ret <0 )return ret;
Yinghai Lu
Acked-byRe: [PATCH v12 01/15] PCI: Let pci_mmap_page_range() take extra resource pointer
Quoted 4 lines · Bjorn Helgaas
Microblaze does look up the resource in
pci_mmap_page_range(), but it never actually uses it. It *looks* like it uses it, but that code is actually dead and I think we should apply the first patch below.
Good one.
Quoted 28 lines
That leaves powerpc as the only arch that would use this extra resource pointer. It uses it in
__pci_mmap_set_pgprot()to help decide whether to make a normal uncacheable mapping or a write- combining one. There's nothing here that's specific to the powerpc architecture, and I don't think we should add this parameter just to cater to powerpc.There are two cases where
__pci_mmap_set_pgprot()on powerpc does something based on the resource:1) We're using procfs to mmap I/O port space after we requested write-combining, e.g., we did this:
ioctl(fd, PCIIOC_MMAP_IS_IO); # request I/O port space
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
mmap(fd, ...)On powerpc, we ignore the write-combining request in this case.
I think we can handle this case by applying the second patch below to ignore write-combining on I/O space for all arches, not just powerpc.
2) We're using sysfs to mmap resourceN (not
resourceN_wc), and the resource is prefetchable. On powerpc, we turn *on* write-combining, even though the user didn't ask for it.
Quoted 9 lines
I'm not sure this case is actually safe, because it changes the ordering properties. If it *is* safe, we could enable write- combining in
pci_mmap_resource(), where we already have the resource and it could be done for all arches.This case is not strictly necessary, except to avoid a performance regression, because the user could have mapped
resourceN_wcto explicitly request write-combining.
Agreed.
Quoted 56 lines
commit
4e712b691abc5b579e3e4327f56b0b7988bdd1cbAuthor: Bjorn Helgaas <[email protected]> Date: Wed Jun 8 14:00:14 2016 -0500microblaze/PCI: Remove useless
__pci_mmap_set_pgprot()The microblaze
__pci_mmap_set_pgprot()was apparently copied from powerpc, where it computes either an uncacheablepgprot_tor a write-combining one. But on microblaze, we always use the regular uncacheablepgprot_t.Remove the useless code in
__pci_mmap_set_pgprot()and inline thepgprot_noncached()at the only caller.Signed-off-by Bjorn Helgaas <[email protected]>arch/microblaze/pci/pci-common.c +0
-27@@ -219,33 +219,6 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, }/* -* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci -* device mapping. -*/ -static pgprot_t __pci_mmap_set_pgprot (struct pci_dev *dev,struct resource *rp, -pgprot_t protection, -enum pci_mmap_state mmap_state, -int write_combine) -{ -pgprot_t prot = protection; - -/* Write combine is always 0 on non-memory space mappings. On -* memory space, if the user didn't pass 1, we check for a -* "prefetchable" resource. This is a bit hackish, but we use -* this to workaround the inability of /sysfs to provide a write -* combine bit -*/ -if (mmap_state != pci_mmap_mem) - write_combine =0 ; -else if (write_combine ==0 ) { -if (rp->flags &IORESOURCE_PREFETCH ) - write_combine =1 ; - } - -return pgprot_noncached (prot); -} - -/* * This one is used by /dev/mem and fbdev who have no clue about the * PCI device, it tries to find the PCI device first and calls the * above routine
arch/microblaze/pci/pci-common.c int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, · line 296
Quoted 10 lines
arch/microblaze/pci/pci-common.c +1
-3@@ -317,9 +290,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,return -EINVAL ; vma->vm_pgoff = offset >>PAGE_SHIFT ; - vma->vm_page_prot =__pci_mmap_set_pgprot (dev, rp, - vma->vm_page_prot, - mmap_state, write_combine); + vma->vm_page_prot =pgprot_noncached (vma->vm_page_prot); ret =remap_pfn_range (vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot);
Quoted 35 lines
commit
962972ee5e0ba6ceb680cb182bad65f8886586a6Author: Bjorn Helgaas <[email protected]> Date: Wed Jun 8 14:46:54 2016 -0500PCI: Ignore write-combining when mapping I/O port space
PCI exposes files like
/proc/bus/pci/00/00.0in procfs. These files support operations like this:
ioctl(fd, PCIIOC_MMAP_IS_IO); # request I/O port space
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
mmap(fd, ...)Many architectures don't allow mmap of I/O port space at all, but I don't think it makes sense to do a write-combining mapping on the ones that do. We could change
proc_bus_pci_ioctl()so the user could never enable write- combining for I/O port space, but that would break the following sequence, which is currently legal:
mmap(fd, ...)# default is I/O, non-combining
ioctl(fd, PCIIOC_WRITE_COMBINE, 1); # request write-combining
ioctl(fd, PCIIOC_MMAP_IS_MEM); # request memory space
mmap(fd, ...)Ignore the write-combining flag when mapping I/O port space.
Signed-off-by Bjorn Helgaas <[email protected]>drivers/pci/proc.c +0
-0
drivers/pci/proc.c static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) · line 254
Quoted 9 lines
drivers/pci/proc.c +2
-1@@ -247,7 +247,8 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) ret =pci_mmap_page_range (dev, vma, fpriv->mmap_state, - fpriv->write_combine); + (fpriv->mmap_state == pci_mmap_mem) ? + fpriv->write_combine :0 );if (ret <0 )return ret;
ok to me.
At the same time, can you kill __pci_mmap_set_pgprot() for powerpc.
arch/powerpc/kernel/pci-common.c +0 -0
@@ -356,36 +356,6 @@ static struct resource
*__pci_mmap_make_offset(struct pci_dev *dev,
}
/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
- pgprot_t protection,
- enum pci_mmap_state mmap_state,
- int write_combine)
-{
-
- /* Write combine is always 0 on non-memory space mappings. On
- * memory space, if the user didn't pass 1, we check for a
- * "prefetchable" resource. This is a bit hackish, but we use
- * this to workaround the inability of /sysfs to provide a write
- * combine bit
- */- if (mmap_state != pci_mmap_mem)
- write_combine = 0;
- else if (write_combine == 0) {
- if (rp->flags & IORESOURCE_PREFETCH)
- write_combine = 1;
- }
-
- /* XXX would be nice to have a way to ask for write-through */
- if (write_combine)
- return pgprot_noncached_wc(protection);
- else
- return pgprot_noncached(protection);
-}
-
-/*
* This one is used by /dev/mem and fbdev who have no clue about the
* PCI device, it tries to find the PCI device first and calls the
* above routine
@@ -458,9 +428,10 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
vma->vm_pgoff = offset >> PAGE_SHIFT;- vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
- vma->vm_page_prot,
- mmap_state, write_combine);
+ if (write_combine)
+ vma->vm_page_prot = pgprot_noncached_wc(protection);
+ else
+ vma->vm_page_prot = pgprot_noncached(protection);
ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);Re: [PATCH v12 01/15] PCI: Let pci_mmap_page_range() take extra resource pointer
Quoted 1 line · Yinghai Lu
At the same time, can you kill
__pci_mmap_set_pgprot()for powerpc.
Can you please put your two patches and this attached one into to pci/next?
Then I could send updated PCI: Let pci_mmap_page_range() take resource address.
Thanks
Yinghai
-------------- next part --------------
A non-text attachment was scrubbed...
Name: remove_powerpc_pci_prot.patch
Type: text/x-patch
Size: 2652 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160608/20950e15/attachment.bin>
Re: [PATCH v12 01/15] PCI: Let pci_mmap_page_range() take extra resource pointer
Quoted 7 lines · Yinghai Lu
Quoted 1 line · Yinghai Lu
At the same time, can you kill
__pci_mmap_set_pgprot()for powerpc.Can you please put your two patches and this attached one into to pci/next?
Then I could send updated PCI: Let
pci_mmap_page_range()take resource address.
Thanks for putting those patches in pci/resource branch.
I just re post updated for second patch.
[v12.update2,02/15] PCI: Let pci_mmap_page_range() take resource address
http://patchwork.ozlabs.org/patch/633399/
And the [v12 01/15] is not needed anymore.
patch3 to patch15 should still can be applied to pci/resource without problem.
Thanks
Yinghai
PATCH v12 2/15 PCI: Let pci_mmap_page_range() take resource address
In reply to Yinghai LuIn 8c05cd08a7 ("PCI: fix offset check for sysfs mmapped files"), try to check exposed value with resource start/end in proc mmap path.
| start = vma->vm_pgoff; | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; | pci_start = (mmap_api = PCI_MMAP_PROCFS) ? | pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0; | if (start >= pci_start && start < pci_start + size && | start + nr <= pci_start + size)
That breaks sparc that exposed value is BAR value, and need to be offseted to resource address.
Original pci_mmap_page_range() is taking PCI BAR value aka usr_address.
Bjorn found out that it would be much simple to pass resource address directly and avoid extra those __pci_mmap_make_offset.
In this patch:
1. in proc path: proc_bus_pci_mmap, try convert back to resource before calling pci_mmap_page_range
2. in sysfs path: pci_mmap_resource will just offset with resource start.
3. all pci_mmap_page_range will have vma->vm_pgoff with in resource range instead of BAR value.
4. remove __pci_mmap_make_offset, as the checking is done
in pci_mmap_fits().
-v2: add pci_user_to_resource and remove __pci_mmap_make_offset -v3: pass resource pointer with pci_mmap_page_range()
--- arch/microblaze/pci/pci-common.c | 78 +++----------------------- arch/powerpc/kernel/pci-common.c | 78 +++----------------------- arch/sparc/kernel/pci.c | 117 --------------------------------------- arch/xtensa/kernel/pci.c | 75 ++++--------------------- drivers/pci/pci-sysfs.c | 33 ++++++++--- drivers/pci/proc.c | 63 ++++++++++++++++++--- 6 files changed, 104 insertions(+), 340 deletions(-)
arch/microblaze/pci/pci-common.c +8 -70
@@ -156,69 +156,6 @@ void pcibios_set_master(struct pci_dev *dev)*/ /* -* Adjust vm_pgoff of VMA such that it is the physical page offset -* corresponding to the 32-bit pci bus offset for DEV requested by the user. -* -* Basically, the user finds the base address for his device which he wishes -* to mmap. They read the 32-bit value from the config space base register, -* add whatever PAGE_SIZE multiple offset they wish, and feed this into the -* offset parameter of mmap on /proc/bus/pci/XXX for that device. -* -* Returns negative error code on failure, zero on success. -*/ -static struct resource *__pci_mmap_make_offset (struct pci_dev *dev, -resource_size_t *offset, -enum pci_mmap_state mmap_state) -{ -struct pci_controller *hose =pci_bus_to_host (dev->bus); -unsigned long io_offset =0 ; -int i, res_bit; - -if (!hose) -return NULL ;/* should never happen */ - -/* If memory, add on the PCI bridge address offset */ -if (mmap_state = pci_mmap_mem) { -#if 0 /* See comment in pci_resource_to_user() for why this is disabled */ - *offset += hose->pci_mem_offset; -#endif - res_bit =IORESOURCE_MEM ; - }else { - io_offset = (unsigned long )hose->io_base_virt - _IO_BASE; - *offset += io_offset; - res_bit =IORESOURCE_IO ; - } - -/* -* Check that the offset requested corresponds to one of the -* resources of the device. -*/ -for (i =0 ; i <=PCI_ROM_RESOURCE ; i++) { -struct resource *rp = &dev->resource[i]; -int flags = rp->flags; - -/* treat ROM as memory (should be already) */ -if (i =PCI_ROM_RESOURCE ) - flags |=IORESOURCE_MEM ; - -/* Active and same type? */ -if ((flags & res_bit) =0 ) -continue ; - -/* In the range of this resource? */ -if (*offset < (rp->start &PAGE_MASK ) || *offset > rp->end) -continue ; - -/* found it! construct the final physical address */ -if (mmap_state = pci_mmap_io) - *offset += hose->io_base_phys - io_offset; -return rp; - } - -return NULL ; -} - -/* * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci * device mapping. */
@@ -310,12 +247,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct resource *rp, { resource_size_t offset ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT; - struct resource *rp;int ret; - rp = __pci_mmap_make_offset(dev, &offset, mmap_state); - if (rp = NULL) - return -EINVAL; + if (mmap_state = pci_mmap_io) { +struct pci_controller *hose =pci_bus_to_host (dev->bus); + +/* hose should never be NULL */ + *offset += hose->io_base_phys - + ((unsigned long )hose->io_base_virt - _IO_BASE); + } vma->vm_pgoff = offset >>PAGE_SHIFT ; vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
@@ -494,9 +434,7 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,* * Hopefully, the sysfs insterface is immune to that gunk. Once X * has been fixed (and the fix spread enough), we can re-enable the -* 2 lines below and pass down a BAR value to userland. In that case -* we'll also have to re-enable the matching code in -* __pci_mmap_make_offset(). +* 2 lines below and pass down a BAR value to userland. * * BenH. */
arch/powerpc/kernel/pci-common.c +8 -70
97 lines not on this page · raw message
arch/sparc/kernel/pci.c +0 -117
129 lines not on this page · raw message
arch/xtensa/kernel/pci.c +9 -65
88 lines not on this page · raw message
drivers/pci/pci-sysfs.c +24 -9
@@ -967,12 +967,23 @@ void pci_remove_legacy_files(struct pci_bus *b)#ifdef HAVE_PCI_MMAP int pci_mmap_fits (struct pci_dev *pdev,int resno,struct vm_area_struct *vma, +enum pci_mmap_state mmap_type,enum pci_mmap_api mmap_api) {unsigned long nr, start, size, pci_start; +int flags;if (pci_resource_len (pdev, resno) =0 )return 0 ; + +if (mmap_type = pci_mmap_mem) + flags =IORESOURCE_MEM ; +else + flags =IORESOURCE_IO ; + +if (!(pci_resource_flags (pdev, resno) & flags)) +return 0 ; + nr =vma_pages (vma); start = vma->vm_pgoff; size = ((pci_resource_len (pdev, resno) -1 ) >>PAGE_SHIFT ) +1 ;
@@ -999,7 +1010,6 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,struct pci_dev *pdev =to_pci_dev (kobj_to_dev (kobj));struct resource *res = attr->private;enum pci_mmap_state mmap_type; -resource_size_t start, end;int i;for (i =0 ; i <PCI_ROM_RESOURCE ; i++)
@@ -1008,10 +1018,21 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,if (i >=PCI_ROM_RESOURCE )return -ENODEV ; +/* +* resource start have to be PAGE_SIZE aligned, as we pass +* back virt address include round down of resource_start, +* that caller can not figure out directly. +* when it is not aligned, that mean it is io port, should go +* pci_read_resource_io()/pci_write_resource_io() path. +*/ +if (res->start & ~PAGE_MASK ) +return -EINVAL ; +if (res->flags &IORESOURCE_MEM &&iomem_is_exclusive (res->start))return -EINVAL ; -if (!pci_mmap_fits (pdev, i, vma,PCI_MMAP_SYSFS )) { + mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; +if (!pci_mmap_fits (pdev, i, vma, mmap_type,PCI_MMAP_SYSFS )) { WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff, pci_name(pdev), i,
@@ -1020,13 +1041,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,return -EINVAL ; } -/* pci_mmap_page_range() expects the same kind of entry as coming -* from /proc/bus/pci/ which is a "user visible" value. If this is -* different from the resource itself, arch will do necessary fixup. -*/ -pci_resource_to_user (pdev, i, res, &start, &end); - vma->vm_pgoff += start >>PAGE_SHIFT ; - mmap_type = res->flags &IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; + vma->vm_pgoff += res->start >>PAGE_SHIFT ;return pci_mmap_page_range (pdev, res, vma, mmap_type, write_combine); }
drivers/pci/proc.c +54 -9
80 lines not on this page · raw message
Signature · 1 line
2.8.3
PATCH v12 3/15 sparc/PCI: Use correct offset for bus address to resource
In reply to Yinghai LuAfter we added 64bit mmio parsing, we got some "no compatible bridge window" warning on anther new model that support 64bit resource.
It turns out that we can not use mem_space.start as 64bit mem space offset, aka there is mem_space.start != offset.
Use child_phys_addr to calculate exact offset and record offset in pbm.
After patch we get correct offset.
/pci@305: PCI IO [io 0x2007e00000000-0x2007e0fffffff] offset 2007e00000000
/pci@305: PCI MEM [mem 0x2000000100000-0x200007effffff] offset 2000000000000
/pci@305: PCI MEM64 [mem 0x2000100000000-0x2000dffffffff] offset 2000000000000
...pci_sun4v f02ae7f8: PCI host bridge to bus 0000:00pci_bus 0000:00: root bus resource [io 0x2007e00000000-0x2007e0fffffff] (bus address [0x0000-0xfffffff]) pci_bus 0000:00: root bus resource [mem 0x2000000100000-0x200007effffff] (bus address [0x00100000-0x7effffff]) pci_bus 0000:00: root bus resource [mem 0x2000100000000-0x2000dffffffff] (bus address [0x100000000-0xdffffffff])
-v3: put back mem64_offset, as we found T4 has mem_offset != mem64_offset
check overlapping between mem64_space and mem_space.
-v7: after new pci_mmap_page_range patches.
--- arch/sparc/kernel/pci.c | 18 +++++++----------- arch/sparc/kernel/pci_common.c | 32 ++++++++++++++++++++++++-------- arch/sparc/kernel/pci_impl.h | 4 ++++ 3 files changed, 35 insertions(+), 19 deletions(-)
arch/sparc/kernel/pci.c +7 -11
@@ -663,12 +663,12 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,printk ("PCI: Scanning PBM %s\n" , node->full_name);pci_add_resource_offset (&resources, &pbm->io_space, - pbm->io_space.start); + pbm->io_offset);pci_add_resource_offset (&resources, &pbm->mem_space, - pbm->mem_space.start); + pbm->mem_offset);if (pbm->mem64_space.flags)pci_add_resource_offset (&resources, &pbm->mem64_space, - pbm->mem_space.start); + pbm->mem64_offset); pbm->busn.start = pbm->pci_first_busno; pbm->busn.end = pbm->pci_last_busno; pbm->busn.flags =IORESOURCE_BUS ;
@@ -870,16 +870,12 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar, const struct resource *rp, resource_size_t *start, resource_size_t *end) { - struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; -unsigned long offset; + struct pci_bus_region region; -if (rp->flags &IORESOURCE_IO ) - offset = pbm->io_space.start; -else - offset = pbm->mem_space.start; +pcibios_resource_to_bus (pdev->bus, ®ion, (struct resource *)rp); - *start = rp->start - offset; - *end = rp->end - offset; + *start = region.start; + *end = region.end; }void pcibios_set_master (struct pci_dev *dev)
arch/sparc/kernel/pci_common.c +24 -8
@@ -410,13 +410,16 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)for (i =0 ; i < num_pbm_ranges; i++) {const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; -unsigned long a, size; +unsigned long a, size, region_a;u32 parent_phys_hi, parent_phys_lo; +u32 child_phys_mid, child_phys_lo;u32 size_hi, size_lo;int type; parent_phys_hi = pr->parent_phys_hi; parent_phys_lo = pr->parent_phys_lo; + child_phys_mid = pr->child_phys_mid; + child_phys_lo = pr->child_phys_lo;if (tlb_type == hypervisor) parent_phys_hi &=0x0fffffff ;
@@ -426,6 +429,8 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) type = (pr->child_phys_hi >>24 ) &0x3 ; a = (((unsigned long )parent_phys_hi <<32UL ) | ((unsigned long )parent_phys_lo <<0UL )); + region_a = (((unsigned long )child_phys_mid <<32UL ) | + ((unsigned long )child_phys_lo <<0UL )); size = (((unsigned long )size_hi <<32UL ) | ((unsigned long )size_lo <<0UL ));
@@ -440,6 +445,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) pbm->io_space.start = a; pbm->io_space.end = a + size -1UL ; pbm->io_space.flags =IORESOURCE_IO ; + pbm->io_offset = a - region_a; saw_io =1 ;break ;
@@ -448,6 +454,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) pbm->mem_space.start = a; pbm->mem_space.end = a + size -1UL ; pbm->mem_space.flags =IORESOURCE_MEM ; + pbm->mem_offset = a - region_a; saw_mem =1 ;break ;
@@ -456,6 +463,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) pbm->mem64_space.start = a; pbm->mem64_space.end = a + size -1UL ; pbm->mem64_space.flags =IORESOURCE_MEM ; + pbm->mem64_offset = a - region_a; saw_mem =1 ;break ;
@@ -471,14 +479,22 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)prom_halt (); } -printk ("%s: PCI IO[%llx] MEM[%llx]" , - pbm->name, - pbm->io_space.start, - pbm->mem_space.start); +if (pbm->io_space.flags) +printk ("%s: PCI IO %pR offset %llx\n" , + pbm->name, &pbm->io_space, pbm->io_offset); +if (pbm->mem_space.flags) +printk ("%s: PCI MEM %pR offset %llx\n" , + pbm->name, &pbm->mem_space, pbm->mem_offset); +if (pbm->mem64_space.flags && pbm->mem_space.flags) { +if (pbm->mem64_space.start <= pbm->mem_space.end) + pbm->mem64_space.start = pbm->mem_space.end +1 ; +if (pbm->mem64_space.start > pbm->mem64_space.end) + pbm->mem64_space.flags =0 ; + } +if (pbm->mem64_space.flags) -printk (" MEM64[%llx]" , - pbm->mem64_space.start); -printk ("\n" ); +printk ("%s: PCI MEM64 %pR offset %llx\n" , + pbm->name, &pbm->mem64_space, pbm->mem64_offset); pbm->io_space.name = pbm->mem_space.name = pbm->name; pbm->mem64_space.name = pbm->name;
arch/sparc/kernel/pci_impl.h +4 -0
@@ -99,6 +99,10 @@ struct pci_pbm_info {struct resource mem_space;struct resource mem64_space;struct resource busn; +/* offset */ +resource_size_t io_offset; +resource_size_t mem_offset; +resource_size_t mem64_offset;/* Base of PCI Config space, can be per-PBM or shared. */ unsigned long config_space;
Signature · 1 line
2.8.3
PATCH v12 4/15 PCI: Add pci_find_bus_resource()
In reply to Yinghai LuAdd pci_find_bus_resource() to return bus resource for input resource.
In some case, we may only have bus instead of dev. It is same as pci_find_parent_resource, but take bus as input.
--- drivers/pci/pci.c | 27 ++++++++++++++++----------- include/linux/pci.h | 2 ++ 2 files changed, 18 insertions(+), 11 deletions(-)
drivers/pci/pci.c +16 -11
@@ -414,18 +414,9 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap) }EXPORT_SYMBOL_GPL (pci_find_ht_capability); -/** -* pci_find_parent_resource - return resource region of parent bus of given region -* @dev: PCI device structure contains resources to be searched -* @res: child resource record for which parent is sought -* -* For given resource region of given device, return the resource -* region of parent bus the given region is contained in. -*/ -struct resource *pci_find_parent_resource (const struct pci_dev *dev, -struct resource *res) +struct resource *pci_find_bus_resource (const struct pci_bus *bus, +struct resource *res) { -const struct pci_bus *bus = dev->bus;struct resource *r;int i;
@@ -455,6 +446,20 @@ struct resource *pci_find_parent_resource(const struct pci_dev *dev, }return NULL ; } + +/** +* pci_find_parent_resource - return resource region of parent bus of given region +* @dev: PCI device structure contains resources to be searched +* @res: child resource record for which parent is sought +* +* For given resource region of given device, return the resource +* region of parent bus the given region is contained in. +*/ +struct resource *pci_find_parent_resource (const struct pci_dev *dev, +struct resource *res) +{ +return pci_find_bus_resource (dev->bus, res); +}EXPORT_SYMBOL (pci_find_parent_resource);/**
include/linux/pci.h +2 -0
@@ -811,6 +811,8 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res);void pcibios_bus_to_resource (struct pci_bus *bus,struct resource *res,struct pci_bus_region *region); +struct resource *pci_find_bus_resource (const struct pci_bus *bus, +struct resource *res);void pcibios_scan_specific_bus (int busn);struct pci_bus *pci_find_bus (int domain,int busnr);void pci_bus_add_devices (const struct pci_bus *bus);
Signature · 1 line
2.8.3
PATCH v12 5/15 sparc/PCI: Reserve legacy mmio after PCI mmio
In reply to Yinghai LuOn one system found bunch of claim resource fail from pci device.pci_sun4v f02b894c: PCI host bridge to bus 0000:00pci_bus 0000:00: root bus resource [io 0x2007e00000000-0x2007e0fffffff] (bus address [0x0000-0xfffffff])pci_bus 0000:00: root bus resource [mem 0x2000000000000-0x200007effffff] (bus address [0x00000000-0x7effffff])pci_bus 0000:00: root bus resource [mem 0x2000100000000-0x20007ffffffff] (bus address [0x100000000-0x7ffffffff])
...
PCI: Claiming 0000:00:02.0: Resource 14: 0002000000000000..00020000004fffff [200]
pci 0000:00:02.0: can't claim BAR 14 [mem 0x2000000000000-0x20000004fffff]: address conflict with Video RAM area [??? 0x20000000a0000-0x20000000bffff flags 0x80000000] pci 0000:02:00.0: can't claim BAR 0 [mem 0x2000000000000-0x20000000fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.0: Resource 3: 0002000000100000..0002000000103fff [200]
pci 0000:02:00.0: can't claim BAR 3 [mem 0x2000000100000-0x2000000103fff]: no compatible bridge window
PCI: Claiming 0000:02:00.1: Resource 0: 0002000000200000..00020000002fffff [200]
pci 0000:02:00.1: can't claim BAR 0 [mem 0x2000000200000-0x20000002fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.1: Resource 3: 0002000000104000..0002000000107fff [200]
pci 0000:02:00.1: can't claim BAR 3 [mem 0x2000000104000-0x2000000107fff]: no compatible bridge window
PCI: Claiming 0000:02:00.2: Resource 0: 0002000000300000..00020000003fffff [200]
pci 0000:02:00.2: can't claim BAR 0 [mem 0x2000000300000-0x20000003fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.2: Resource 3: 0002000000108000..000200000010bfff [200]
pci 0000:02:00.2: can't claim BAR 3 [mem 0x2000000108000-0x200000010bfff]: no compatible bridge window
PCI: Claiming 0000:02:00.3: Resource 0: 0002000000400000..00020000004fffff [200]
pci 0000:02:00.3: can't claim BAR 0 [mem 0x2000000400000-0x20000004fffff]: no compatible bridge window
PCI: Claiming 0000:02:00.3: Resource 3: 000200000010c000..000200000010ffff [200]
pci 0000:02:00.3: can't claim BAR 3 [mem 0x200000010c000-0x200000010ffff]: no compatible bridge window
The bridge 00:02.0 resource does not get reserved as Video RAM take the position early, and following children resources reservation all fail.
Move down Video RAM area reservation after pci mmio get reserved, so we leave pci driver to use those regions.
-v5: merge simplify one and use pcibios_bus_to_resource()
-v6: use pci_find_bus_resource()
--- arch/sparc/kernel/pci.c | 1 + arch/sparc/kernel/pci_common.c | 59 ++++++++++++++++++++++-------------------- arch/sparc/kernel/pci_impl.h | 1 + 3 files changed, 33 insertions(+), 28 deletions(-)
arch/sparc/kernel/pci.c +1 -0
@@ -686,6 +686,7 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,pci_bus_register_of_sysfs (bus);pci_claim_bus_resources (bus); +pci_register_legacy_regions (bus);pci_bus_add_devices (bus);return bus; }
arch/sparc/kernel/pci_common.c +31 -28
80 lines not on this page · raw message
arch/sparc/kernel/pci_impl.h +1 -0
@@ -167,6 +167,7 @@ void pci_get_pbm_props(struct pci_pbm_info *pbm);struct pci_bus *pci_scan_one_pbm (struct pci_pbm_info *pbm,struct device *parent);void pci_determine_mem_io_space (struct pci_pbm_info *pbm); +void pci_register_legacy_regions (struct pci_bus *bus);/* Error reporting support. */ void pci_scan_for_target_abort (struct pci_pbm_info *,struct pci_bus *);
Signature · 1 line
2.8.3
PATCH v12 6/15 sparc/PCI: Add IORESOURCE_MEM_64 for 64-bit resource in OF parsing
In reply to Yinghai LuFor device resource with PREF bit setting under bridge 64-bit pref resource, we need to make sure only set PREF for 64bit resource.
so this patch set IORESOUCE_MEM_64 for 64bit resource during OF device resource flags parsing.
--- arch/sparc/kernel/of_device_32.c | 5 +++-- arch/sparc/kernel/of_device_64.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-)
arch/sparc/kernel/of_device_32.c +3 -2
@@ -83,11 +83,12 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)case 0x01 : flags |=IORESOURCE_IO ;break ; -case 0x02 :/* 32 bits */ -case 0x03 :/* 64 bits */ flags |=IORESOURCE_MEM ;break ; +case 0x03 :/* 64 bits */ + flags |=IORESOURCE_MEM |IORESOURCE_MEM_64 ; +break ; }if (w &0x40000000 ) flags |=IORESOURCE_PREFETCH ;
arch/sparc/kernel/of_device_64.c +3 -2
@@ -146,11 +146,12 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)case 0x01 : flags |=IORESOURCE_IO ;break ; -case 0x02 :/* 32 bits */ -case 0x03 :/* 64 bits */ flags |=IORESOURCE_MEM ;break ; +case 0x03 :/* 64 bits */ + flags |=IORESOURCE_MEM |IORESOURCE_MEM_64 ; +break ; }if (w &0x40000000 ) flags |=IORESOURCE_PREFETCH ;
Signature · 1 line
2.8.3
PATCH v12 7/15 sparc/PCI: Keep resource idx order with bridge register number
In reply to Yinghai LuOn one system found strange "no compatible bridge window" warning even we already had pref_compat support that add extra pref bit for device resource.
PCI: Claiming 0000:00:01.0: Resource 14: 0002000100000000..000200010fffffff [10220c]
PCI: Claiming 0000:01:00.0: Resource 1: 0002000100000000..000200010000ffff [100214]
pci 0000:01:00.0: can't claim BAR 1 [mem 0x2000100000000-0x200010000ffff 64bit]: no compatible bridge window
It turns out that pci_resource_compatible()/pci_up_path_over_pref_mem64() just check resource with bridge pref mmio register idx 15, and we have put resource to use mmio register idx 14 during of_scan_pci_bridge() as the bridge does not have mmio resource.
We already fix pci_up_path_over_pref_mem64() to check all bus resources.
And at the same time, this patch make resource to have consistent sequence like other arch or directly from pci_read_bridge_bases(),
even when non-pref mmio is missing, or out of ordering in firmware reporting.
Just hold i = 1 for non pref mmio, and i = 2 for pref mmio.
--- arch/sparc/kernel/pci.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
arch/sparc/kernel/pci.c +7 -1
@@ -481,7 +481,7 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,pci_read_bridge_bases (bus); goto after_ranges; } - i =1 ; + i =3 ;for (; len >=32 ; len -=32 , ranges +=8 ) {u64 start;
@@ -513,6 +513,12 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm, " for bridge %s\n", node->full_name);continue ; } + }else if ((flags &IORESOURCE_PREFETCH ) && + !bus->resource[2 ]->flags) { + res = bus->resource[2 ]; + }else if (((flags & (IORESOURCE_MEM |IORESOURCE_PREFETCH )) = +IORESOURCE_MEM ) && !bus->resource[1 ]->flags) { + res = bus->resource[1 ]; }else {if (i >=PCI_NUM_RESOURCES -PCI_BRIDGE_RESOURCES ) { printk(KERN_ERR "PCI: too many memory ranges"
Signature · 1 line
2.8.3
PATCH v12 8/15 powerpc/PCI: Keep resource idx order with bridge register number
In reply to Yinghai LuSame as sparc version.
Make resource with consistent sequence
like other arch or directly from pci_read_bridge_bases(),
even when non-pref mmio is missing, or out of ordering in firmware reporting.
Just hold i = 1 for non pref mmio, and i = 2 for pref mmio.
--- arch/powerpc/kernel/pci_of_scan.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
arch/powerpc/kernel/pci_of_scan.c +7 -1
@@ -252,7 +252,7 @@ void of_scan_pci_bridge(struct pci_dev *dev) bus->resource[i] = res; ++res; } - i =1 ; + i =3 ;for (; len >=32 ; len -=32 , ranges +=8 ) { flags =pci_parse_of_flags (of_read_number (ranges,1 ),1 ); size =of_read_number (&ranges[6 ],2 );
@@ -265,6 +265,12 @@ void of_scan_pci_bridge(struct pci_dev *dev) " for bridge %s\n", node->full_name);continue ; } + }else if ((flags &IORESOURCE_PREFETCH ) && + !bus->resource[2 ]->flags) { + res = bus->resource[2 ]; + }else if (((flags & (IORESOURCE_MEM |IORESOURCE_PREFETCH )) == +IORESOURCE_MEM ) && !bus->resource[1 ]->flags) { + res = bus->resource[1 ]; }else {if (i >=PCI_NUM_RESOURCES -PCI_BRIDGE_RESOURCES ) { printk(KERN_ERR "PCI: too many memory ranges"
Signature · 1 line
2.8.3
PATCH v12 9/15 powerpc/PCI: Add IORESOURCE_MEM_64 for 64-bit resource in OF parsing
In reply to Yinghai LuFor device resource PREF bit setting under bridge 64-bit pref resource, we need to make sure only set PREF for 64bit resource.
This patch set IORESOUCE_MEM_64 for 64bit resource during OF device resource flags parsing.
--- arch/powerpc/kernel/pci_of_scan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/powerpc/kernel/pci_of_scan.c +3 -1
@@ -44,8 +44,10 @@ static unsigned int pci_parse_of_flags(u32 addr0, int bridge)if (addr0 &0x02000000 ) { flags =IORESOURCE_MEM |PCI_BASE_ADDRESS_SPACE_MEMORY ; - flags |= (addr0 >>22 ) &PCI_BASE_ADDRESS_MEM_TYPE_64 ; flags |= (addr0 >>28 ) &PCI_BASE_ADDRESS_MEM_TYPE_1M ; +if (addr0 &0x01000000 ) + flags |=IORESOURCE_MEM_64 + |PCI_BASE_ADDRESS_MEM_TYPE_64 ;if (addr0 &0x40000000 ) flags |=IORESOURCE_PREFETCH |PCI_BASE_ADDRESS_MEM_PREFETCH ;
Signature · 1 line
2.8.3
PATCH v12 10/15 OF/PCI: Add IORESOURCE_MEM_64 for 64-bit resource
In reply to Yinghai LuFor device resource PREF bit setting under bridge 64-bit pref resource, we need to make sure only set PREF for 64bit resource.
This patch set IORESOUCE_MEM_64 for 64bit resource during OF device resource flags parsing.
--- drivers/of/address.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/of/address.c +3 -1
@@ -129,9 +129,11 @@ static unsigned int of_bus_pci_get_flags(const __be32 *addr) flags |=IORESOURCE_IO ;break ;case 0x02 :/* 32 bits */ -case 0x03 :/* 64 bits */ flags |=IORESOURCE_MEM ;break ; +case 0x03 :/* 64 bits */ + flags |=IORESOURCE_MEM |IORESOURCE_MEM_64 ; +break ; }if (w &0x40000000 ) flags |=IORESOURCE_PREFETCH ;
Signature · 1 line
2.8.3
PATCH v12 11/15 PCI: Check pref compatible bit for mem64 resource of PCIe device
In reply to Yinghai LuWe still get "no compatible bridge window" warning on sparc T5-8 after we add support for 64bit resource parsing for root bus.
PCI: scan_bus[/pci@300/pci@1/pci@0/pci@6] bus no 8
PCI: Claiming 0000:00:01.0: Resource 15: 0000800100000000..00008004afffffff [220c]
PCI: Claiming 0000:01:00.0: Resource 15: 0000800100000000..00008004afffffff [220c]
PCI: Claiming 0000:02:04.0: Resource 15: 0000800100000000..000080012fffffff [220c]
PCI: Claiming 0000:03:00.0: Resource 15: 0000800100000000..000080012fffffff [220c]
PCI: Claiming 0000:04:06.0: Resource 14: 0000800100000000..000080010fffffff [220c]
PCI: Claiming 0000:05:00.0: Resource 0: 0000800100000000..0000800100001fff [204]
pci 0000:05:00.0: can't claim BAR 0 [mem 0x800100000000-0x800100001fff]: no compatible bridge window
All the bridges 64-bit resource have pref bit, but the device resource does not have pref set, then we can not find parent for the device resource, as we can not put non-pref mmio under pref mmio.
According to pcie spec errta
https://www.pcisig.com/specifications/pciexpress/base2/PCIe_Base_r2.1_Errata_08Jun10.pdf
page 13, in some case it is ok to mark some as pref.
Mark if the entire path from the host to the adapter is over PCI Express. Set pref compatible bit for claim/sizing/assign for 64bit mem resource on that pcie device.
-v2: set pref for mmio 64 when whole path is PCI Express, according to David Miller. -v3: don't set pref directly, change to UNDER_PREF, and set PREF before
sizing and assign resource, and cleart PREF afterwards. requested by BenH.
-v4: use on_all_pcie_path device flag instead.
-v6: update after pci_find_bus_resource() change
--- arch/sparc/kernel/pci_common.c | 2 +- drivers/pci/pci.c | 8 +++++--- drivers/pci/pci.h | 2 ++ drivers/pci/probe.c | 33 +++++++++++++++++++++++++++++++++ drivers/pci/setup-bus.c | 23 +++++++++++++++++++---- drivers/pci/setup-res.c | 4 ++++ include/linux/pci.h | 3 ++- 7 files changed, 66 insertions(+), 9 deletions(-)
arch/sparc/kernel/pci_common.c +1 -1
@@ -343,7 +343,7 @@ static void pci_register_region(struct pci_bus *bus, const char *name, region.start = rstart; region.end = rstart + size -1UL ;pcibios_bus_to_resource (bus, res, ®ion); - bus_res =pci_find_bus_resource (bus, res); + bus_res =pci_find_bus_resource (bus, res, res->flags);if (!bus_res) {kfree (res);return ;
drivers/pci/pci.c +5 -3
@@ -415,7 +415,7 @@ int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)EXPORT_SYMBOL_GPL (pci_find_ht_capability);struct resource *pci_find_bus_resource (const struct pci_bus *bus, -struct resource *res) +struct resource *res,int flags) {struct resource *r;int i;
@@ -430,7 +430,7 @@ struct resource *pci_find_bus_resource(const struct pci_bus *bus,* not, the allocator made a mistake. */ if (r->flags &IORESOURCE_PREFETCH && - !(res->flags &IORESOURCE_PREFETCH )) + !(flags &IORESOURCE_PREFETCH ))return NULL ;/*
@@ -458,7 +458,9 @@ struct resource *pci_find_bus_resource(const struct pci_bus *bus,struct resource *pci_find_parent_resource (const struct pci_dev *dev,struct resource *res) { -return pci_find_bus_resource (dev->bus, res); +int flags =pci_resource_pref_compatible (dev, res); + +return pci_find_bus_resource (dev->bus, res, flags); }EXPORT_SYMBOL (pci_find_parent_resource);
drivers/pci/pci.h +2 -0
@@ -336,4 +336,6 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) }#endif +int pci_resource_pref_compatible (const struct pci_dev *dev, +struct resource *res);#endif /* DRIVERS_PCI_H */
drivers/pci/probe.c +33 -0
@@ -1732,6 +1732,36 @@ static void pci_dma_configure(struct pci_dev *dev)pci_put_host_bridge_device (bridge); } +static bool pci_up_path_over_pcie (struct pci_bus *bus) +{ +if (pci_is_root_bus (bus)) +return true; + +if (bus->self && !pci_is_pcie (bus->self)) +return false; + +return pci_up_path_over_pcie (bus->parent); +} + +/* +* According to +* https://www.pcisig.com/specifications/pciexpress/base2/PCIe_Base_r2.1_Errata_08Jun10.pdf +* page 13, system firmware could put some 64bit non-pref under 64bit pref, +* on some cases. +* Let's mark if entire path from the host to the adapter is over PCI +* Express. later will use that compute pref compaitable bit. +*/ +static void pci_set_on_all_pcie_path (struct pci_dev *dev) +{ +if (!pci_is_pcie (dev)) +return ; + +if (!pci_up_path_over_pcie (dev->bus)) +return ; + + dev->on_all_pcie_path =1 ; +} +void pci_device_add (struct pci_dev *dev,struct pci_bus *bus) {int ret;
@@ -1762,6 +1792,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)/* Initialize various capabilities */ pci_init_capabilities (dev); +/* After pcie_cap is assigned */ +pci_set_on_all_pcie_path (dev); +/* * Add the device to our list of discovered devices * and the bus list for fixup functions, etc.
drivers/pci/setup-bus.c +19 -4
@@ -738,6 +738,20 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)return -EINVAL ; } +int pci_resource_pref_compatible (const struct pci_dev *dev, +struct resource *res) +{ +if (res->flags &IORESOURCE_PREFETCH ) +return res->flags; + +if ((res->flags &IORESOURCE_MEM ) && + (res->flags &IORESOURCE_MEM_64 ) && + dev->on_all_pcie_path) +return res->flags |IORESOURCE_PREFETCH ; + +return res->flags; +} +/* Check whether the bridge supports optional I/O and prefetchable memory ranges. If not, the respective base/limit registers must be read-only and read as 0. */
@@ -1035,11 +1049,12 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,for (i =0 ; i <PCI_NUM_RESOURCES ; i++) {struct resource *r = &dev->resource[i];resource_size_t r_size; +int flags =pci_resource_pref_compatible (dev, r); -if (r->parent || (r->flags &IORESOURCE_PCI_FIXED ) || - ((r->flags & mask) != type && - (r->flags & mask) != type2 && - (r->flags & mask) != type3)) +if (r->parent || (flags &IORESOURCE_PCI_FIXED ) || + ((flags & mask) != type && + (flags & mask) != type2 && + (flags & mask) != type3))continue ; r_size =resource_size (r);#ifdef CONFIG_PCI_IOV
drivers/pci/setup-res.c +4 -0
@@ -257,15 +257,19 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,static int _pci_assign_resource (struct pci_dev *dev,int resno,resource_size_t size,resource_size_t min_align) { +struct resource *res = dev->resource + resno; +int old_flags = res->flags;struct pci_bus *bus;int ret; + res->flags =pci_resource_pref_compatible (dev, res); bus = dev->bus;while ((ret =__pci_assign_resource (bus, dev, resno, size, min_align))) {if (!bus->parent || !bus->self->transparent)break ; bus = bus->parent; } + res->flags = old_flags;return ret; }
include/linux/pci.h +2 -1
@@ -309,6 +309,7 @@ struct pci_dev {powered on/off by the corresponding bridge */ unsigned int ignore_hotplug:1; /* Ignore hotplug events */ + unsigned int on_all_pcie_path:1; /* up to host-bridge all pcie */unsigned int d3_delay;/* D3->D0 transition time in ms */ unsigned int d3cold_delay;/* D3cold->D0 transition time in ms */
@@ -812,7 +813,7 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,void pcibios_bus_to_resource (struct pci_bus *bus,struct resource *res,struct pci_bus_region *region);struct resource *pci_find_bus_resource (const struct pci_bus *bus, -struct resource *res); +struct resource *res,int flags);void pcibios_scan_specific_bus (int busn);struct pci_bus *pci_find_bus (int domain,int busnr);void pci_bus_add_devices (const struct pci_bus *bus);
Signature · 6 lines
2.8.3 -- To unsubscribe from this list: send the line "unsubscribe sparclinux" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v12 12/15 PCI: Only treat non-pref mmio64 as pref if all bridges have MEM_64
In reply to Yinghai LuIf any bridge up to root only have 32bit pref mmio, We don't need to treat device non-pref mmio64 as as pref mmio64.
We need to move pci_bridge_check_ranges calling early.
For parent bridges pref mmio BAR may not allocated by BIOS, res flags is still 0, we need to have it correct set before we check them for child device resources.
-v2: check all bus resources instead of just res[15].
--- drivers/pci/setup-bus.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-)
drivers/pci/setup-bus.c +29 -2
@@ -738,6 +738,29 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)return -EINVAL ; } +static bool pci_up_path_over_pref_mem64 (struct pci_bus *bus) +{ +if (pci_is_root_bus (bus)) +return true; + +if (bus->self) { +int i; +bool found = false; +struct resource *res; + +pci_bus_for_each_resource (bus, res, i) +if (res->flags &IORESOURCE_MEM_64 ) { + found = true; +break ; + } + +if (!found) +return false; + } + +return pci_up_path_over_pref_mem64 (bus->parent); +} +int pci_resource_pref_compatible (const struct pci_dev *dev,struct resource *res) {
@@ -746,7 +769,8 @@ int pci_resource_pref_compatible(const struct pci_dev *dev,if ((res->flags &IORESOURCE_MEM ) && (res->flags &IORESOURCE_MEM_64 ) && - dev->on_all_pcie_path) + dev->on_all_pcie_path && +pci_up_path_over_pref_mem64 (dev->bus))return res->flags |IORESOURCE_PREFETCH ;return res->flags;
@@ -1239,6 +1263,10 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)struct resource *b_res;int ret; +if (!pci_is_root_bus (bus) && + (bus->self->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ) +pci_bridge_check_ranges (bus); +list_for_each_entry (dev, &bus->devices, bus_list) {struct pci_bus *b = dev->subordinate;if (!b)
@@ -1266,7 +1294,6 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)break ;case PCI_CLASS_BRIDGE_PCI : -pci_bridge_check_ranges (bus);if (bus->self->is_hotplug_bridge) { additional_io_size = pci_hotplug_io_size; additional_mem_size = pci_hotplug_mem_size;
Signature · 1 line
2.8.3
PATCH v12 13/15 PCI: Add has_mem64 for struct host_bridge
In reply to Yinghai LuAdd has_mem64 for struct host_bridge, on root bus that does not support mmio64 above 4g, will not set that.
We will use that info next two following patches:
1. Don't treat non-pref mmio64 as pref mmio, so will not put it under bridge's pref range when rescan the devices
2. will keep pref mmio64 and pref mmio32 under bridge pref bar.
--- drivers/pci/probe.c | 7 +++++++ include/linux/pci.h | 1 + 2 files changed, 8 insertions(+)
drivers/pci/probe.c +7 -0
@@ -2231,6 +2231,13 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, }else bus_addr[0 ] ='\0' ;dev_info (&b->dev,"root bus resource %pR%s\n" , res, bus_addr); + +if (resource_type (res) ==IORESOURCE_MEM ) { +if ((res->end - offset) >0xffffffff ) + bridge->has_mem64 =1 ; +if ((res->start - offset) >0xffffffff ) + res->flags |=IORESOURCE_MEM_64 ; + } }down_write (&pci_bus_sem);
include/linux/pci.h +1 -0
@@ -412,6 +412,7 @@ struct pci_host_bridge {void (*release_fn)(struct pci_host_bridge *);void *release_data; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ + unsigned int has_mem64:1;/* Resource alignment requirements */ resource_size_t (*align_resource)(struct pci_dev *dev, const struct resource *res,
Signature · 1 line
2.8.3
PATCH v12 14/15 PCI: Only treat non-pref mmio64 as pref if host bridge has mmio64
In reply to Yinghai LuIf host bridge does not have mmio64 above 4G, We don't need to treat device non-pref mmio64 as as pref mmio64.
--- drivers/pci/setup-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/setup-bus.c +1 -1
@@ -741,7 +741,7 @@ int pci_claim_bridge_resource(struct pci_dev *bridge, int i)static bool pci_up_path_over_pref_mem64 (struct pci_bus *bus) {if (pci_is_root_bus (bus)) -return true; +return to_pci_host_bridge (bus->bridge)->has_mem64;if (bus->self) {int i;
Signature · 1 line
2.8.3
PATCH v12 15/15 PCI: Restore pref MMIO allocation logic for host bridge without mmio64
In reply to Yinghai LuQuoted 1 line
From
5b2854155(PCI: Restrict 64-bit prefetchable bridge windows to 64-bit
resources), we change the logic for pref mmio allocation:
When bridge pref support mmio64, we will only put children pref that support mmio64 into it, and will put children pref mmio32 into bridge's non-pref mmio32.
That could leave bridge pref bar not used when that pref bar is mmio64, and children res only has mmio32.
Also could have allocation failure when non-pref mmio32 is not big enough space for those children pref mmio32.
That is not rational when the host bridge does not have 64bit mmio above 4g at all.
The patch restore to old logic:
when host bridge does not have has_mem64, put children pref mmio64 and pref mmio32 all under bridges pref bars.
--- drivers/pci/bus.c | 4 +++- drivers/pci/setup-bus.c | 13 +++++++++---- drivers/pci/setup-res.c | 9 ++++++--- 3 files changed, 18 insertions(+), 8 deletions(-)
drivers/pci/bus.c +3 -1
@@ -204,8 +204,10 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, {#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT int rc; +unsigned long mmio64 =pci_find_host_bridge (bus)->has_mem64 ? +IORESOURCE_MEM_64 :0 ; -if (res->flags &IORESOURCE_MEM_64 ) { +if (res->flags & mmio64) { rc =pci_bus_alloc_from_region (bus, res, size, align, min, type_mask, alignf, alignf_data, &pci_high);
drivers/pci/setup-bus.c +9 -4
@@ -1311,7 +1311,8 @@ void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head) b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES ]; mask =IORESOURCE_MEM ; prefmask =IORESOURCE_MEM |IORESOURCE_PREFETCH ; -if (b_res[2 ].flags &IORESOURCE_MEM_64 ) { +if ((b_res[2 ].flags &IORESOURCE_MEM_64 ) && +pci_find_host_bridge (bus)->has_mem64) { prefmask |=IORESOURCE_MEM_64 ; ret = pbus_size_mem(bus, prefmask, prefmask, prefmask, prefmask,
@@ -1513,17 +1514,21 @@ static void pci_bridge_release_resources(struct pci_bus *bus,* io port. * 2. if there is non pref mmio assign fail, release bridge * nonpref mmio. -* 3. if there is 64bit pref mmio assign fail, and bridge pref +* 3. if there is pref mmio assign fail, and host bridge does +* have 64bit mmio, release bridge pref mmio. +* 4. if there is 64bit pref mmio assign fail, and bridge pref * is 64bit, release bridge pref mmio. -* 4. if there is pref mmio assign fail, and bridge pref is +* 5. if there is pref mmio assign fail, and bridge pref is * 32bit mmio, release bridge pref mmio -* 5. if there is pref mmio assign fail, and bridge pref is not +* 6. if there is pref mmio assign fail, and bridge pref is not * assigned, release bridge nonpref mmio. */ if (type &IORESOURCE_IO ) idx =0 ;else if (!(type &IORESOURCE_PREFETCH )) idx =1 ; +else if (!pci_find_host_bridge (bus)->has_mem64) + idx =2 ;else if ((type &IORESOURCE_MEM_64 ) && (b_res[2 ].flags &IORESOURCE_MEM_64 )) idx =2 ;
drivers/pci/setup-res.c +6 -3
@@ -212,6 +212,8 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,struct resource *res = dev->resource + resno;resource_size_t min;int ret; +unsigned long mmio64 =pci_find_host_bridge (bus)->has_mem64 ? +IORESOURCE_MEM_64 :0 ; min = (res->flags &IORESOURCE_IO ) ?PCIBIOS_MIN_IO :PCIBIOS_MIN_MEM ;
@@ -223,7 +225,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,* things differently than they were sized, not everything will fit. */ ret =pci_bus_alloc_resource (bus, res, size, align, min, -IORESOURCE_PREFETCH |IORESOURCE_MEM_64 , +IORESOURCE_PREFETCH | mmio64, pcibios_align_resource, dev);if (ret ==0 )return 0 ;
@@ -232,7 +234,8 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,* If the prefetchable window is only 32 bits wide, we can put * 64-bit prefetchable resources in it. */ -if ((res->flags & (IORESOURCE_PREFETCH |IORESOURCE_MEM_64 )) == +if (mmio64 && + (res->flags & (IORESOURCE_PREFETCH |IORESOURCE_MEM_64 )) == (IORESOURCE_PREFETCH |IORESOURCE_MEM_64 )) { ret = pci_bus_alloc_resource(bus, res, size, align, min, IORESOURCE_PREFETCH,
@@ -247,7 +250,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,* non-prefetchable, the first call already tried the only possibility * so we don't need to try again. */ -if (res->flags & (IORESOURCE_PREFETCH |IORESOURCE_MEM_64 )) +if (res->flags & (IORESOURCE_PREFETCH | mmio64)) ret =pci_bus_alloc_resource (bus, res, size, align, min,0 , pcibios_align_resource, dev);
Signature · 1 line
2.8.3