PCI: Let pci_mmap_page_range() extra resource pointer
Subsystems (10)
RFC PATCH v3 1/2 PCI: Let pci_mmap_page_range() 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#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
@@ -605,7 +605,8 @@ int pcibios_enable_device(struct pci_devreturn 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 *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_merg#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, cons }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_busextern 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/mips/include/asm/pci.h +0 -3
@@ -77,9 +77,6 @@ extern void pcibios_set_master(struct pc#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
@@ -322,7 +322,8 @@ void pcibios_fixup_bus(struct pci_bus *bEXPORT_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(str }#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(voidpcibios_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#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(v } -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_busextern 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/sh/drivers/pci/pci.c +2 -1
@@ -269,7 +269,8 @@ void __init_refok pcibios_report_status( } } -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, PCIstruct 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#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/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_devreturn 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_d#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 .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
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);
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: */
arch/microblaze/pci/pci-common.c +2 -1
@@ -302,7 +302,8 @@ pgprot_t pci_phys_mem_access_prot(struct* * 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/powerpc/kernel/pci-common.c +2 -1
@@ -445,7 +445,8 @@ pgprot_t pci_phys_mem_access_prot(struct* * 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/sparc/kernel/pci.c +2 -1
@@ -862,7 +862,8 @@ static void __pci_mmap_set_pgprot(struct* * 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/xtensa/kernel/pci.c +2 -1
@@ -362,7 +362,8 @@ __pci_mmap_set_pgprot(struct pci_dev *de* * 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 kobjpci_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 fileif (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 )
RFC PATCH v3 2/2 PCI: Let pci_mmap_page_range() take resource address
In 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 would break sparc that exposed value is BAR value.
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 to avoid extra those __pci_mmap_make_offset again.
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
@@ -154,69 +154,6 @@ void pcibios_set_master(struct pci_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. */
@@ -308,12 +245,15 @@ int pci_mmap_page_range(struct pci_dev * {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,
@@ -492,9 +432,7 @@ void pci_resource_to_user(const struct p* * 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
98 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 +10 -65
89 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_#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 kobjstruct 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 kobjif (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 kobjreturn -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