Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH 00/17] PCI resource mmap cleanup

84 views
Skip to first unread message

David Woodhouse

unread,
Mar 22, 2017, 9:40:05 AM3/22/17
to
This started out as a fairly trivial "add pci_mmap_page_range() for
ARM64" patch. But pci_mmap_page_range() is a vile interface, taking
"user visible" resource addresses converted with pci_resource_to_user()
on those platforms unlucky enough to use that... and even in the *sane*
sysfs-based mmap method, we convert through user addresses to call the
platform-specific method.

In most cases there's just no need for any of this crap. We can migrate
most architectures to a generic implementation without much thought,
and the few that aren't converted in this series can probably be added
fairly easily too but need a little more arch-specific attention.

Utterly untested for now; I'll do some testing while I deal with the
inevitable bikeshedding.

David Woodhouse (17):
pci: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
pci: Fix another sanity check bug in /proc/pci mmap
pci: Only allow WC mmap on prefetchable resources
pci: Add arch_can_pci_mmap_wc() macro
pci: Move multiple declarations of pci_mmap_page_range() to <linux/pci.h>
pci: Add HAVE_PCI_MMAP_IO to architectures which can mmap() I/O space
pci: Use BAR index in sysfs attr->private instead of resource pointer
pci: Add BAR index argument to pci_mmap_page_range()
pci: Add pci_mmap_resource_range() and use it for ARM64
arm: Use generic pci_mmap_resource_range()
cris: Use generic pci_mmap_resource_range()
mips: Use generic pci_mmap_resource_range()
mn10300: Use generic pci_mmap_resource_range()
parisc: Use generic pci_mmap_resource_range()
sh: Use generic pci_mmap_resource_range()
unicore: Use generic pci_mmap_resource_range()
arm64: Do not expose PCI mmap through procfs

Documentation/filesystems/sysfs-pci.txt | 9 +++-
arch/arm/include/asm/pci.h | 3 +-
arch/arm/kernel/bios32.c | 19 -------
arch/arm64/include/asm/pci.h | 3 ++
arch/cris/arch-v32/drivers/pci/bios.c | 22 --------
arch/cris/include/asm/pci.h | 4 +-
arch/ia64/include/asm/pci.h | 4 +-
arch/ia64/pci/pci.c | 3 +-
arch/microblaze/include/asm/pci.h | 6 +--
arch/microblaze/pci/pci-common.c | 2 +-
arch/mips/include/asm/pci.h | 5 +-
arch/mips/pci/pci.c | 24 ---------
arch/mn10300/include/asm/pci.h | 4 +-
arch/mn10300/unit-asb2305/pci-asb2305.c | 23 ---------
arch/parisc/include/asm/pci.h | 4 +-
arch/parisc/kernel/pci.c | 28 ----------
arch/powerpc/include/asm/pci.h | 9 ++--
arch/powerpc/kernel/pci-common.c | 3 +-
arch/sh/drivers/pci/pci.c | 21 --------
arch/sh/include/asm/pci.h | 4 +-
arch/sparc/include/asm/pci_64.h | 5 +-
arch/sparc/kernel/pci.c | 6 +--
arch/unicore32/include/asm/pci.h | 3 +-
arch/unicore32/kernel/pci.c | 23 ---------
arch/x86/include/asm/pci.h | 6 +--
arch/x86/pci/i386.c | 3 +-
arch/xtensa/include/asm/pci.h | 11 ++--
arch/xtensa/kernel/pci.c | 5 +-
drivers/pci/Makefile | 2 +-
drivers/pci/mmap.c | 90 +++++++++++++++++++++++++++++++++
drivers/pci/pci-sysfs.c | 77 +++++++++++++---------------
drivers/pci/proc.c | 55 ++++++++++++++------
include/linux/pci.h | 19 +++++++
33 files changed, 233 insertions(+), 272 deletions(-)
create mode 100644 drivers/pci/mmap.c

--
2.9.3

David Woodhouse

unread,
Mar 22, 2017, 9:40:07 AM3/22/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/sh/drivers/pci/pci.c | 22 ----------------------
arch/sh/include/asm/pci.h | 1 +
2 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index c8b36b7..c99ee28 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -269,28 +269,6 @@ void __ref pcibios_report_status(unsigned int status_mask, int warn)
}
}

-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- /*
- * I/O space can be accessed via normal processor loads and stores on
- * this platform but for now we elect not to do this and portable
- * drivers should not do this anyway.
- */
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- /*
- * Ignore write-combine; for now only return uncached mappings.
- */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-}
-
#ifndef CONFIG_GENERIC_IOMAP

void __iomem *__pci_ioport_map(struct pci_dev *dev,
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 46abbc9..17fa69b 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -66,6 +66,7 @@ extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
struct pci_dev;

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

extern void pcibios_set_master(struct pci_dev *dev);

--
2.9.3

David Woodhouse

unread,
Mar 22, 2017, 9:40:07 AM3/22/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Most of the almost-identical versions of pci_mmap_page_range() silently
ignore the 'write_combine' argument and give uncached mappings.

Yet we allow the PCIIOC_WRITE_COMBINE ioctl in /proc/bus/pci, expose the
'resourceX_wc' file in sysfs, and allow an attempted mapping to apparently
succeed.

To fix this, introduce a macro arch_can_pci_mmap_wc() which indicates
whether the platform can do a write-combining mapping. On x86 this ends
up being pat_enabled(), while the few other platforms that support it
can just set it to a literal '1'.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Documentation/filesystems/sysfs-pci.txt | 4 ++++
arch/ia64/include/asm/pci.h | 2 ++
arch/powerpc/include/asm/pci.h | 5 +++--
arch/x86/include/asm/pci.h | 2 ++
arch/xtensa/include/asm/pci.h | 6 +++++-
arch/xtensa/kernel/pci.c | 2 +-
drivers/pci/pci-sysfs.c | 6 ++++--
drivers/pci/proc.c | 17 ++++++++++-------
8 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 6ea1ced..25b7f1c 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -117,6 +117,10 @@ code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function.
Platforms are free to only support subsets of the mmap functionality, but
useful return codes should be provided.

+Platforms which support write-combining maps of PCI resources must define
+arch_can_pci_mmap_wc() which shall evaluate to non-zero at runtime when
+write-combining is permitted.
+
Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms
wishing to support legacy functionality should define it and provide
pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index c0835b0..6283758 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -51,6 +51,8 @@ extern unsigned long ia64_max_iommu_merge_mask;
#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL)

#define HAVE_PCI_MMAP
+#define arch_can_pci_mmap_wc() 1
+
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
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 93eded8..b5b68c6 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -81,8 +81,9 @@ struct vm_area_struct;
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
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() and it does WC */
+#define HAVE_PCI_MMAP 1
+#define arch_can_pci_mmap_wc() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
size_t count);
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 1411dbe..f6e22c2 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -7,6 +7,7 @@
#include <linux/string.h>
#include <linux/scatterlist.h>
#include <asm/io.h>
+#include <asm/pat.h>
#include <asm/x86_init.h>

#ifdef __KERNEL__
@@ -102,6 +103,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);


#define HAVE_PCI_MMAP
+#define arch_can_pci_mmap_wc() pat_enabled()
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine);
diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index 5d6bd93..f106879 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -51,7 +51,11 @@ 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
+#define HAVE_PCI_MMAP 1
+
+/* This was wrapped in #if 0 since the first merge of xtensa support...
+#define arch_can_pci_mmap_wc() 1
+*/

#endif /* __KERNEL__ */

diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index b848cc3..c5944d3 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -345,7 +345,7 @@ __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,

/* Set to write-through */
prot = (prot & _PAGE_CA_MASK) | _PAGE_CA_WT;
-#if 0
+#ifdef arch_can_pci_mmap_wc
if (!write_combine)
prot |= _PAGE_WRITETHRU;
#endif
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7ac258f..cf2c7d8 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1210,10 +1210,12 @@ static int pci_create_resource_files(struct pci_dev *pdev)
continue;

retval = pci_create_attr(pdev, i, 0);
+#ifdef arch_can_pci_mmap_wc
/* for prefetchable resources, create a WC mappable file */
- if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH)
+ if (!retval && arch_can_pci_mmap_wc() &&
+ pdev->resource[i].flags & IORESOURCE_PREFETCH)
retval = pci_create_attr(pdev, i, 1);
-
+#endif
if (retval) {
pci_remove_resource_files(pdev);
return retval;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index dc8912e..c49be71 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -209,15 +209,18 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
fpriv->mmap_state = pci_mmap_mem;
break;

+#ifdef arch_can_pci_mmap_wc
case PCIIOC_WRITE_COMBINE:
- if (arg)
- fpriv->write_combine = 1;
- else
- fpriv->write_combine = 0;
- break;
-
+ if (arch_can_pci_mmap_wc()) {
+ if (arg)
+ fpriv->write_combine = 1;
+ else
+ fpriv->write_combine = 0;
+ break;
+ }
+ /* If arch decided it can't, fall through... */
+#endif /* arch_can_pci_mmap_wc */
#endif /* HAVE_PCI_MMAP */
-
default:
ret = -EINVAL;
break;
--
2.9.3

David Woodhouse

unread,
Mar 22, 2017, 9:40:08 AM3/22/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/arm/include/asm/pci.h | 1 +
arch/arm/kernel/bios32.c | 20 --------------------
2 files changed, 1 insertion(+), 20 deletions(-)

diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 51118a0..396c92b 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -29,6 +29,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
#define PCI_DMA_BUS_IS_PHYS (1)

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index a4fc3f4..b259956 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -597,26 +597,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}

-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- /*
- * Mark this as IO
- */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
-
void __init pci_map_io_early(unsigned long pfn)
{
struct map_desc pci_io_desc = {
--
2.9.3

David Woodhouse

unread,
Mar 22, 2017, 9:40:12 AM3/22/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
drivers/pci/proc.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 2d9cfa4..a940f4b 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -17,6 +17,11 @@

static int proc_initialized; /* = 0 */

+#ifdef __aarch64__
+/* ARM64 wants to be special and not expose this through /proc like everyone else */
+#undef HAVE_PCI_MMAP
+#endif
+
static loff_t proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
struct pci_dev *dev = PDE_DATA(file_inode(file));
--
2.9.3

Sinan Kaya

unread,
Mar 22, 2017, 10:00:06 AM3/22/17
to
On 3/22/2017 9:25 AM, David Woodhouse wrote:
>
> +#ifdef __aarch64__
> +/* ARM64 wants to be special and not expose this through /proc like everyone else */
> +#undef HAVE_PCI_MMAP
> +#endif
> +

Where is this ARM64 special requirement coming from?

--
Sinan Kaya
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project.

David Woodhouse

unread,
Mar 22, 2017, 10:10:08 AM3/22/17
to
On Wed, 2017-03-22 at 09:54 -0400, Sinan Kaya wrote:
> On 3/22/2017 9:25 AM, David Woodhouse wrote:
> >
> >  
> > +#ifdef __aarch64__
> > +/* ARM64 wants to be special and not expose this through /proc
> > like everyone else */
> > +#undef HAVE_PCI_MMAP
> > +#endif
> > +
> Where is this ARM64 special requirement coming from?

The idea is that as a new platform, ARM64 shouldn't need to implement
legacy userspace interfaces.

http://lists.infradead.org/pipermail/linux-arm-kernel/2016-April/422571.html

Will Deacon

unread,
Mar 22, 2017, 10:20:07 AM3/22/17
to
On Wed, Mar 22, 2017 at 10:15:04AM -0400, Sinan Kaya wrote:
> Aren't we breaking an ABI for userspace? I know DPDK relies on this feature.

It relies on the /proc interface? That's the first I've ever heard of that
-- everybody so far has only been interested in the sysfs stuff.

Nothing's more broken than before, because we've never supported the /proc
interface, but if existing arm64 code out there is failing because of that
then I'm of course open to supporting it. I'm just surprised that nobody
else has come up with that before, since DPDK is in common use.

Can you point me at the specific code, please?

Will

Sinan Kaya

unread,
Mar 22, 2017, 10:20:07 AM3/22/17
to
On 3/22/2017 10:04 AM, David Woodhouse wrote:
Aren't we breaking an ABI for userspace? I know DPDK relies on this feature.

Sinan Kaya

unread,
Mar 22, 2017, 11:50:06 AM3/22/17
to
I'm correcting myself. I had to go back my memory from last year.

DPDK requires HAVE_PCI_MMAP to be set. We have been carrying
some old maillist patch around for DPDK customers internally.

When HAVE_PCI_MMAP is set, resource files are created in sysfs and procfs.
DPDK is using the files in sysfs directory not procfs directory.

Having HAVE_PCI_MMAP defined is the DPDK requirement.

>
> Will

David Woodhouse

unread,
Mar 23, 2017, 10:30:06 AM3/23/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Actually it turns out this is fairly trivial for x86 too; it just looked
more interesting at first glance. But pgprot_writecombine() and
pgprot_device() will both do the right thing here, and allowing WC
conditionally based on pat_enabled() is already working so we'll never
get asked to do that when we don't want to.

arch/x86/include/asm/pci.h | 1 +
arch/x86/pci/i386.c | 48 ----------------------------------------------
2 files changed, 1 insertion(+), 48 deletions(-)

diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 734cc94..f513cc2 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -104,6 +104,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);

#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() pat_enabled()
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#ifdef CONFIG_PCI
extern void early_quirks(void);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 8ca5e5d..68499cf 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -406,51 +406,3 @@ void __init pcibios_resource_survey(void)
*/
ioapic_insert_resources();
}
-
-static const struct vm_operations_struct pci_mmap_ops = {
- .access = generic_access_phys,
-};
-
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long prot;
-
- /* I/O space cannot be accessed via normal processor loads and
- * stores on this platform.
- */
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- prot = pgprot_val(vma->vm_page_prot);
-
- /*
- * Return error if pat is not enabled and write_combine is requested.
- * Caller can followup with UC MINUS request and add a WC mtrr if there
- * is a free mtrr slot.
- */
- if (!pat_enabled() && write_combine)
- return -EINVAL;
-
- if (pat_enabled() && write_combine)
- prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
- else if (pat_enabled() || boot_cpu_data.x86 > 3)
- /*
- * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
- * To avoid attribute conflicts, request UC MINUS here
- * as well.
- */
- prot |= cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
-
- vma->vm_page_prot = __pgprot(prot);
-
- if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- vma->vm_ops = &pci_mmap_ops;
-
- return 0;
-}
--
2.9.3

David Woodhouse

unread,
Mar 24, 2017, 7:50:04 AM3/24/17
to
On Wed, 2017-03-22 at 13:25 +0000, David Woodhouse wrote:
> This started out as a fairly trivial "add pci_mmap_page_range() for 
> ARM64" patch. But pci_mmap_page_range() is a vile interface, taking 
> "user visible" resource addresses converted with pci_resource_to_user() 
> on those platforms unlucky enough to use that... and even in the *sane* 
> sysfs-based mmap method, we convert through user addresses to call the
> platform-specific method.
>
> In most cases there's just no need for any of this crap. We can migrate
> most architectures to a generic implementation without much thought,
> and the few that aren't converted in this series can probably be added
> fairly easily too but need a little more arch-specific attention.
>
> Utterly untested for now; I'll do some testing while I deal with the
> inevitable bikeshedding.

I added PowerPC too. Rather than posting it here as patches 18/17 and
19/17 I'll just point at 
http://git.infradead.org/users/dwmw2/random-2.6.git/shortlog/refs/heads/pcimmap

To support pci_mmap_io I added a pci_iobar_pfn() function which the
arch must provide, to adjust vma->vm_pgoff to the physical address of
the I/O window of the appropriate PCI host controller. It looks
something like this:

int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
resource_size_t ioaddr = pci_resource_start(pdev, bar);

if (!hose)
return -EINVAL;

/* Convert to an offset within this PCI controller */
ioaddr -= (unsigned long)hose->io_base_virt - _IO_BASE;

vma->vm_pgoff += (ioaddr + hose->io_base_phys) >> PAGE_SHIFT;
return 0;
}

It looks like SPARC, xtensa and Microblaze can all do the same thing,
as they were all basically the same code in the first place.
That leaves IA64 as the last holdout, as the selection of vm_page_prot
there is rather complicated:

prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
    vma->vm_page_prot);

/*
* If the user requested WC, the kernel uses UC or WC for this region,
* and the chipset supports WC, we can use WC. Otherwise, we have to
* use the same attribute the kernel uses.
*/
if (write_combine &&
    ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC ||
     (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) &&
    efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
else
vma->vm_page_prot = prot;


But I suspect it's *overcomplicated*, as the kernel should only ever be
mapping PCI memory BARs as UC or WC in the first place, so the middle
two checks in the if (write_combine…) condition are redundant.

And if the efi_range_is_wc() check isn't gratuitous, perhaps that
should be in the generic code whenever CONFIG_EFI is set?

Tony?

> David Woodhouse (17):
>   pci: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
>   pci: Fix another sanity check bug in /proc/pci mmap
>   pci: Only allow WC mmap on prefetchable resources
>   pci: Add arch_can_pci_mmap_wc() macro
>   pci: Move multiple declarations of pci_mmap_page_range() to

Arnd Bergmann

unread,
Mar 24, 2017, 12:20:05 PM3/24/17
to
On Wed, Mar 22, 2017 at 2:25 PM, David Woodhouse <dw...@infradead.org> wrote:
> From: David Woodhouse <dw...@amazon.co.uk>
>
> Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
> ---
> drivers/pci/proc.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
> index 2d9cfa4..a940f4b 100644
> --- a/drivers/pci/proc.c
> +++ b/drivers/pci/proc.c
> @@ -17,6 +17,11 @@
>
> static int proc_initialized; /* = 0 */
>
> +#ifdef __aarch64__
> +/* ARM64 wants to be special and not expose this through /proc like everyone else */
> +#undef HAVE_PCI_MMAP
> +#endif

I'd still prefer this to be a whitelist of the existing architectures using PCI
MMAP in procfs, there is really no reason for arm64 to be special, the
one thing we want to control here is whether new architectures (including
arm64) that have never had either the sysfs or the procfs interface
should get one or both of them.

As it seems that there are important use cases for the sysfs interface
and your patch series will just make that work everywhere, I'd argue
that we should just always provide the sysfs interface now, and use
HAVE_PCI_MMAP only control the procfs interface.

That way, we turn on the sysfs interface on arc, arm64, frv and tile
as well as any future architecture with PCI support, but leave
the procfs support as opt-in.

Arnd

Arnd Bergmann

unread,
Mar 24, 2017, 12:20:06 PM3/24/17
to
Something alone these lines, to replace your patch 17/17 and the
one that turns on HAVE_PCI_MMAP for arm64.

Signed-off-by: Arnd Bergmann <ar...@arndb.de>

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 25d010d449a3..c517f1b724e0 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -980,8 +980,6 @@ void pci_remove_legacy_files(struct pci_bus *b)
}
#endif /* HAVE_PCI_LEGACY */

-#ifdef HAVE_PCI_MMAP
-
int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
{
@@ -1217,10 +1215,6 @@ static int pci_create_resource_files(struct
pci_dev *pdev)
}
return 0;
}
-#else /* !HAVE_PCI_MMAP */
-int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
-void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
-#endif /* HAVE_PCI_MMAP */

/**
* pci_write_rom - used to enable access to the PCI ROM display
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 8dd38e69d6f2..6c2a15d4ebf9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -21,14 +21,12 @@ void pci_create_firmware_label_files(struct pci_dev *pdev);
void pci_remove_firmware_label_files(struct pci_dev *pdev);
#endif
void pci_cleanup_rom(struct pci_dev *dev);
-#ifdef HAVE_PCI_MMAP
enum pci_mmap_api {
PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
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);
-#endif
int pci_probe_reset_function(struct pci_dev *dev);

/**

Arnd Bergmann

unread,
Mar 24, 2017, 12:30:06 PM3/24/17
to
On Wed, Mar 22, 2017 at 2:25 PM, David Woodhouse <dw...@infradead.org> wrote:
> This started out as a fairly trivial "add pci_mmap_page_range() for
> ARM64" patch. But pci_mmap_page_range() is a vile interface, taking
> "user visible" resource addresses converted with pci_resource_to_user()
> on those platforms unlucky enough to use that... and even in the *sane*
> sysfs-based mmap method, we convert through user addresses to call the
> platform-specific method.
>
> In most cases there's just no need for any of this crap. We can migrate
> most architectures to a generic implementation without much thought,
> and the few that aren't converted in this series can probably be added
> fairly easily too but need a little more arch-specific attention.
>
> Utterly untested for now; I'll do some testing while I deal with the
> inevitable bikeshedding.

Looks good to me overall, I have replied with one request for
clarification, and would like the bikeshed in patch 17 in a different
colour.

Arnd

David Woodhouse

unread,
Mar 24, 2017, 12:30:06 PM3/24/17
to
On Fri, 2017-03-24 at 17:13 +0100, Arnd Bergmann wrote:
>
> I'd still prefer this to be a whitelist of the existing architectures using PCI
> MMAP in procfs, there is really no reason for arm64 to be special, the
> one thing we want to control here is whether new architectures (including
> arm64) that have never had either the sysfs or the procfs interface
> should get one or both of them.
>
> As it seems that there are important use cases for the sysfs interface
> and your patch series will just make that work everywhere, I'd argue
> that we should just always provide the sysfs interface now, and use
> HAVE_PCI_MMAP only control the procfs interface.

I still have no sympathy for the "we don't want <this> tiny part of the
legacy generic non-architecture-specific procfs ABI to exist on ARM64".
Why not just kill /proc/bus/pci *entirely* there?

But sure, I suppose we could refactor things so that the sysfs mmap
bits depend on (HAVE_PCI_MMAP || ARCH_GENERIC_MMAP_RESOURCE_RANGE)
rather than having architectures define the latter in *addition* to the
former.

> That way, we turn on the sysfs interface on arc, arm64, frv and tile
> as well as any future architecture with PCI support, but leave
> the procfs support as opt-in.

OK. My plan was for ARCH_GENERIC_MMAP_RESOURCE_RANGE to go away once
all architectures were converted, and HAVE_PCI_MMAP to be all that's
left. It does make send to do arc, fr-v and tile too though. So we can
do it that way.

David Woodhouse

unread,
Mar 24, 2017, 12:30:07 PM3/24/17
to
On Fri, 2017-03-24 at 17:16 +0100, Arnd Bergmann wrote:
>
> Something alone these lines, to replace your patch 17/17 and the
> one that turns on HAVE_PCI_MMAP for arm64.

No, I think that won't build because you don't have a
pci_mmap_page_range() function. And you didn't define
ARCH_GENERIC_PCI_MMAP_RESOURCE_RANGE. You probably get away with it if
you just fix up the ARCH_GENERIC_PCI_MMAP_RESOURCE_RANGE checks in
drivers/pci/mmap.c to be !HAVE_PCI_MMAP?

Luck, Tony

unread,
Mar 24, 2017, 1:00:05 PM3/24/17
to
On Fri, Mar 24, 2017 at 11:40:33AM +0000, David Woodhouse wrote:
> That leaves IA64 as the last holdout, as the selection of vm_page_prot
> there is rather complicated:
>
> prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
>     vma->vm_page_prot);
>
> /*
> * If the user requested WC, the kernel uses UC or WC for this region,
> * and the chipset supports WC, we can use WC. Otherwise, we have to
> * use the same attribute the kernel uses.
> */
> if (write_combine &&
>     ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC ||
>      (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) &&
>     efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
> vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
> else
> vma->vm_page_prot = prot;
>
>
> But I suspect it's *overcomplicated*, as the kernel should only ever be
> mapping PCI memory BARs as UC or WC in the first place, so the middle
> two checks in the if (write_combine…) condition are redundant.

Agreed.

> And if the efi_range_is_wc() check isn't gratuitous, perhaps that
> should be in the generic code whenever CONFIG_EFI is set?

Sounds dubious whether EFI could even get this right. The efi
memory map table is static, but we could remap a BAR to a different
spot. Does the efi map have entries for all the places that you
could remap a BAR? Isn't it more likely a property of the device
whether it supports WC?

-Tony

Bjorn Helgaas

unread,
Apr 4, 2017, 5:40:07 PM4/4/17
to
This hunk seems like maybe it should be a separate patch.

The rest of the patch:

- skips creation of /sys/.../resourceX_wc if !arch_can_pci_mmap_wc()
- makes PCIIOC_WRITE_COMBINE fail if !arch_can_pci_mmap_wc()

This part seems different -- it changes the way pci_mmap_page_range()
works.
Can we get rid of these #ifdefs in the code by adding this to linux/pci.h?

#ifndef arch_can_pci_mmap_wc
#define arch_can_pci_mmap_wc() 0
#endif

Bjorn Helgaas

unread,
Apr 4, 2017, 6:50:04 PM4/4/17
to
On Wed, Mar 22, 2017 at 01:25:14PM +0000, David Woodhouse wrote:
> This started out as a fairly trivial "add pci_mmap_page_range() for
> ARM64" patch. But pci_mmap_page_range() is a vile interface, taking
> "user visible" resource addresses converted with pci_resource_to_user()
> on those platforms unlucky enough to use that... and even in the *sane*
> sysfs-based mmap method, we convert through user addresses to call the
> platform-specific method.
>
> In most cases there's just no need for any of this crap. We can migrate
> most architectures to a generic implementation without much thought,
> and the few that aren't converted in this series can probably be added
> fairly easily too but need a little more arch-specific attention.
>
> Utterly untested for now; I'll do some testing while I deal with the
> inevitable bikeshedding.

This looks really nice; thanks a lot for doing this!

I agree with Arnd about the __aarch64__ ifdef in pci/proc.c; I'd rather get
rid of that if we can.

I think you had a couple other updates; can you post a v2 when you're done
with those?

David Woodhouse

unread,
Apr 5, 2017, 3:30:07 AM4/5/17
to
On Tue, 2017-04-04 at 16:36 -0500, Bjorn Helgaas wrote:
> > --- a/arch/xtensa/kernel/pci.c
> > +++ b/arch/xtensa/kernel/pci.c
> > @@ -345,7 +345,7 @@ __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
> >  
> >   /* Set to write-through */
> >   prot = (prot & _PAGE_CA_MASK) | _PAGE_CA_WT;
> > -#if 0
> > +#ifdef arch_can_pci_mmap_wc
>
> This hunk seems like maybe it should be a separate patch.
>
> ...
>
> This part seems different -- it changes the way pci_mmap_page_range()
> works.

It doesn't, because arch_can_pci_map_wc isn't defined on xtensa. So
it's just a trivial cleanup for future-proofing, turning that 'if 0'
into 'if <something that isn't set>'.

> > diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
> > index dc8912e..c49be71 100644
> > --- a/drivers/pci/proc.c
> > +++ b/drivers/pci/proc.c
> > @@ -209,15 +209,18 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
> >   fpriv->mmap_state = pci_mmap_mem;
> >   break;
> >  
> > +#ifdef arch_can_pci_mmap_wc
> Can we get rid of these #ifdefs in the code by adding this to linux/pci.h?
>
>   #ifndef arch_can_pci_mmap_wc
>   #define arch_can_pci_mmap_wc() 0
>   #endif

Er.... at the time, that was non-trivial because there was something
that actually needed to be *removed* with the preprocessor instead of
just not being called. But after I settled on the incremental approach
of having pci_mmap_resource_range() be a wrapper for
pci_mmap_page_range() *and* vice versa I think that requirement went
away. I'll take another look and see if I can do that now; thanks.

Are you happy with the suggestion that we use HAVE_PCI_MMAP *only* to
control mmap on /proc/bus/pci, and we present mmap through sysfs on all
platforms via the generic code?

David Woodhouse

unread,
Apr 12, 2017, 8:30:05 AM4/12/17
to
This pursues my previous patch set all the way to its logical conclusion.

It kills off the legacy arch-provided pci_mmap_page_range() completely,
along with its vile 'address converted by pci_resource_to_user()' API
and the various bugs and other strange behaviour that various
architectures had.

In some cases like IA64 I've killed off the odd behaviour *first* in
separately reviewable patches, before the final switch over to the
generic code which should then basically have no functional effect.

To accommodate the ARM64 maintainers' desire *not* to support mmap
through /proc/bus/pci I have separated HAVE_PCI_MMAP from the sysfs
implementation, which (as of the last patch in the series) ends up
present on *all* platforms with an MMU. I still don't think that's a
*good* idea though; it's a generic part of /proc, and nobody ever did
answer my question about what *else* we can delete from /proc on ARM64
"because it's a new platform"...

I would very much like the interesting parts of this to go through the
arch maintainers' trees. I'd suggest that we can pull everything up to
and including patch 19 ("pci: Add I/O BAR support to generic
pci_mmap_resource_range()") through the PCI tree, which includes the
relatively trivial architectures. Then the others can go through the
appropriate arch tree with more careful review and testing.

Once everything's done, then we can apply something like the final
patch ("pci: Kill ARCH_GENERIC_PCI_MMAP_RESOURCE"). But that's mostly
just there for now as a demonstration of the intended end point.

This is in
git://git.infradead.org/users/dwmw2/random-2.6.git pcimmap
http://git.infradead.org/users/dwmw2/random-2.6.git/shortlog/refs/heads/pcimmap

David Woodhouse (27):
pci: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
pci: Fix another sanity check bug in /proc/pci mmap
pci: Only allow WC mmap on prefetchable resources
xtensa: Do not mmap PCI BARs to userspace as write-through
pci: Add arch_can_pci_mmap_wc() macro
pci: Move multiple declarations of pci_mmap_page_range() to
<linux/pci.h>
pci: Add arch_can_pci_mmap_io() on architectures which can mmap() I/O
space
pci: Use BAR index in sysfs attr->private instead of resource pointer
pci: Add BAR index argument to pci_mmap_page_range()
pci: Add pci_mmap_resource_range() and use it for ARM64
arm: Use generic pci_mmap_resource_range()
cris: Use generic pci_mmap_resource_range()
mips: Use generic pci_mmap_resource_range()
mn10300: Use generic pci_mmap_resource_range()
parisc: Use generic pci_mmap_resource_range()
sh: Use generic pci_mmap_resource_range()
unicore: Use generic pci_mmap_resource_range()
x86: Use generic pci_mmap_resource_range()
pci: Add I/O BAR support to generic pci_mmap_resource_range()
powerpc: Use generic pci_mmap_resource_range()
microblaze: Use generic pci_mmap_resource_range()
xtensa: Use generic pci_mmap_resource_range()
ia64: Remove redundant valid_mmap_phys_addr_range() from
pci_mmap_page_range()
ia64: Remove redundant checks for WC in pci_mmap_page_range()
ia64: Use generic pci_mmap_resource_range()
sparc: Use generic pci_mmap_resource_range()
pci: Kill ARCH_GENERIC_PCI_MMAP_RESOURCE

Documentation/filesystems/sysfs-pci.txt | 12 ++-
arch/arm/include/asm/pci.h | 2 -
arch/arm/kernel/bios32.c | 19 ----
arch/cris/arch-v32/drivers/pci/bios.c | 22 -----
arch/cris/include/asm/pci.h | 3 -
arch/ia64/include/asm/pci.h | 4 +-
arch/ia64/pci/pci.c | 46 ----------
arch/microblaze/include/asm/pci.h | 8 +-
arch/microblaze/pci/pci-common.c | 99 ++------------------
arch/mips/include/asm/pci.h | 4 -
arch/mips/pci/pci.c | 24 -----
arch/mn10300/include/asm/pci.h | 3 -
arch/mn10300/unit-asb2305/pci-asb2305.c | 23 -----
arch/parisc/include/asm/pci.h | 3 -
arch/parisc/kernel/pci.c | 28 ------
arch/powerpc/include/asm/pci.h | 9 +-
arch/powerpc/kernel/pci-common.c | 105 +++-------------------
arch/sh/drivers/pci/pci.c | 21 -----
arch/sh/include/asm/pci.h | 3 +-
arch/sparc/include/asm/pci_64.h | 5 +-
arch/sparc/kernel/pci.c | 155 --------------------------------
arch/unicore32/include/asm/pci.h | 2 -
arch/unicore32/kernel/pci.c | 23 -----
arch/x86/include/asm/pci.h | 6 +-
arch/x86/pci/i386.c | 47 ----------
arch/xtensa/include/asm/pci.h | 9 +-
arch/xtensa/kernel/pci.c | 112 ++---------------------
drivers/pci/Makefile | 1 +
drivers/pci/mmap.c | 67 ++++++++++++++
drivers/pci/pci-sysfs.c | 76 +++++++---------
drivers/pci/pci.h | 4 +-
drivers/pci/proc.c | 41 ++++++---
include/linux/pci.h | 30 +++++++
33 files changed, 211 insertions(+), 805 deletions(-)

David Woodhouse

unread,
Apr 12, 2017, 8:30:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Now that every architecture does it, we can kill the #define. This does have
the side-effect that other architectures which previously didn't support
mmap on sysfs resource files now get it.

We have an exemption for !MMU (obviously) and for Alpha (with its bizarre
setup for pre-BWX CPUs).

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Documentation/filesystems/sysfs-pci.txt | 11 +++--------
arch/arm/include/asm/pci.h | 1 -
arch/arm64/include/asm/pci.h | 2 --
arch/cris/include/asm/pci.h | 1 -
arch/ia64/include/asm/pci.h | 1 -
arch/microblaze/include/asm/pci.h | 1 -
arch/mips/include/asm/pci.h | 1 -
arch/mn10300/include/asm/pci.h | 1 -
arch/parisc/include/asm/pci.h | 1 -
arch/powerpc/include/asm/pci.h | 1 -
arch/sh/include/asm/pci.h | 1 -
arch/sparc/include/asm/pci_64.h | 1 -
arch/unicore32/include/asm/pci.h | 1 -
arch/x86/include/asm/pci.h | 1 -
arch/xtensa/include/asm/pci.h | 1 -
drivers/pci/Makefile | 3 ++-
drivers/pci/mmap.c | 20 --------------------
drivers/pci/pci-sysfs.c | 2 +-
18 files changed, 6 insertions(+), 45 deletions(-)

diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 06f1d64..0aff2fe 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -112,14 +112,9 @@ to access legacy memory space.
Supporting PCI access on new platforms
--------------------------------------

-In order to support PCI resource mapping as described above, Linux platform
-code should ideally define ARCH_GENERIC_PCI_MMAP_RESOURCE and use the generic
-implementation of that functionality. To support the historical interface of
-mmap() through files in /proc/bus/pci, platforms may also set HAVE_PCI_MMAP.
-
-Alternatively, platforms which set HAVE_PCI_MMAP may provide their own
-implementation of pci_mmap_page_range() instead of defining
-ARCH_GENERIC_PCI_MMAP_RESOURCE.
+To support the historical interface of mmap() through files in /proc/bus/pci,
+platforms may also set HAVE_PCI_MMAP. The mapping through sysfs is supported
+through generic code.

Platforms which support write-combining maps of PCI resources must define
arch_can_pci_mmap_wc() which shall evaluate to non-zero at runtime when
diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 396c92b..51118a0 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -29,7 +29,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
#define PCI_DMA_BUS_IS_PHYS (1)

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
index 1fc1974..b9a7ba9 100644
--- a/arch/arm64/include/asm/pci.h
+++ b/arch/arm64/include/asm/pci.h
@@ -22,8 +22,6 @@
*/
#define PCI_DMA_BUS_IS_PHYS (0)

-#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
-
extern int isa_dma_bridge_buggy;

#ifdef CONFIG_PCI
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index 6e50533..65198cb 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -42,7 +42,6 @@ struct pci_dev;
#define PCI_DMA_BUS_IS_PHYS (1)

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 6459f2d..fc60b3d 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -51,7 +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
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define arch_can_pci_mmap_wc() 1

#define HAVE_PCI_LEGACY
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 97452c0..9080e40 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -49,7 +49,6 @@ struct vm_area_struct;

/* Tell PCI code what kind of PCI resource mappings we support */
#define HAVE_PCI_MMAP 1
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
#define arch_can_pci_mmap_io() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 1000c1b..15e9fe9 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -110,7 +110,6 @@ extern unsigned long PCIBIOS_MIN_MEM;
extern void pcibios_set_master(struct pci_dev *dev);

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define HAVE_ARCH_PCI_RESOURCE_TO_USER

/*
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index d276549..082b6de 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -74,7 +74,6 @@ static inline int pci_controller_num(struct pci_dev *dev)
}

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index 1de1a3f..bb9ea90 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -200,6 +200,5 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
}

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __ASM_PARISC_PCI_H */
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index edd5b0d..cce93be 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -80,7 +80,6 @@ struct vm_area_struct;

/* Tell PCI code what kind of PCI resource mappings we support */
#define HAVE_PCI_MMAP 1
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
#define arch_can_pci_mmap_io() 1
#define arch_can_pci_mmap_wc() 1

diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 17fa69b..46abbc9 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -66,7 +66,6 @@ extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
struct pci_dev;

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

extern void pcibios_set_master(struct pci_dev *dev);

diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index b8206d5..b957ca5 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -42,7 +42,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
/* Platform support for /proc/bus/pci/X/Y mmap()s. */

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define arch_can_pci_mmap_io() 1
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
#define get_pci_unmapped_area get_fb_unmapped_area
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index ac5acdf..a5129086 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -17,7 +17,6 @@
#include <mach/hardware.h> /* for PCIBIOS_MIN_* */

#define HAVE_PCI_MMAP
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */
#endif
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index f513cc2..734cc94 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -104,7 +104,6 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);

#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() pat_enabled()
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#ifdef CONFIG_PCI
extern void early_quirks(void);
diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index 0ddb411..50bf4e1 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -48,7 +48,6 @@ struct pci_dev;

/* Tell PCI code what kind of PCI resource mappings we support */
#define HAVE_PCI_MMAP 1
-#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
#define arch_can_pci_mmap_io() 1

#endif /* __KERNEL__ */
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 3d40e41..39fafe2 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,8 @@

obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o mmap.o
+ irq.o vpd.o setup-bus.o vc.o
+obj-$(CONFIG_MMU) += mmap.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o

diff --git a/drivers/pci/mmap.c b/drivers/pci/mmap.c
index 16e1d70..090902c4 100644
--- a/drivers/pci/mmap.c
+++ b/drivers/pci/mmap.c
@@ -15,7 +15,6 @@
#include <linux/mm.h>
#include <linux/pci.h>

-#ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
/* Modern setup: generic pci_mmap_resource_range(), and implement the legacy
* pci_mmap_page_range() (if needed) as a wrapper round it. */

@@ -66,22 +65,3 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot);
}
-
-#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */
-/* Legacy setup: Impement pci_mmap_resource_range() as a wrapper around
- the architecture's pci_mmap_page_range(), converting to "user visible"
- addresses as necessary. */
-int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- resource_size_t start, end;
- /* 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, bar, &pdev->resource[bar], &start, &end);
- vma->vm_pgoff += start >> PAGE_SHIFT;
- return pci_mmap_page_range(pdev, bar, vma, mmap_state, write_combine);
-}
-#endif
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 10feb98..fe32ef8 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -980,7 +980,7 @@ void pci_remove_legacy_files(struct pci_bus *b)
}
#endif /* HAVE_PCI_LEGACY */

-#if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
+#if defined(CONFIG_MMU) && !defined(__alpha__)

int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

We can declare it <linux/pci.h> even on platforms where it isn't going
to be defined. There's no need to have it littered through the various
<asm/pci.h> files.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/arm/include/asm/pci.h | 2 --
arch/cris/include/asm/pci.h | 3 ---
arch/ia64/include/asm/pci.h | 2 --
arch/microblaze/include/asm/pci.h | 3 ---
arch/mips/include/asm/pci.h | 3 ---
arch/mn10300/include/asm/pci.h | 3 ---
arch/parisc/include/asm/pci.h | 3 ---
arch/powerpc/include/asm/pci.h | 3 ---
arch/sh/include/asm/pci.h | 3 +--
arch/sparc/include/asm/pci_64.h | 4 ----
arch/unicore32/include/asm/pci.h | 2 --
arch/x86/include/asm/pci.h | 4 ----
arch/xtensa/include/asm/pci.h | 4 ----
include/linux/pci.h | 7 +++++++
14 files changed, 8 insertions(+), 38 deletions(-)

diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 057d381..51118a0 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -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)
{
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index b1b289d..65198cb 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -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__ */

diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 6283758..fc60b3d 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -53,8 +53,6 @@ extern unsigned long ia64_max_iommu_merge_mask;
#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() 1

-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,
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index 2a120bb..ab381d2 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -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
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 30d1129..3141e2a 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -111,9 +111,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

/*
diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 51159ff..082b6de 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -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__ */

diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
index defebd9..bb9ea90 100644
--- a/arch/parisc/include/asm/pci.h
+++ b/arch/parisc/include/asm/pci.h
@@ -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 */
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index b5b68c6..55887d1 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -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() and it does WC */
#define HAVE_PCI_MMAP 1
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 644314f..46abbc9 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -66,8 +66,7 @@ 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.
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 2303635..516fda7 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -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;
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index 37e55d0..a5129086 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -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
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index f6e22c2..734cc94 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -104,10 +104,6 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);

#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() pat_enabled()
-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);
diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index 5d6bd93..bb5510b 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -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

diff --git a/include/linux/pci.h b/include/linux/pci.h
index e614fb4..e7bb4b62 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1626,6 +1626,13 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }

#include <asm/pci.h>

+/* Map a range of PCI memory or I/O space for a device into user space.
+ * Architectures provide this function if they set HAVE_PCI_MMAP, and
+ * it accepts the 'write_combine' argument when arch_can_pci_mmap_wc()
+ * evaluates to nonzero. */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine);
+
#ifndef arch_can_pci_mmap_wc
#define arch_can_pci_mmap_wc() 0
#endif
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/cris/arch-v32/drivers/pci/bios.c | 23 -----------------------
arch/cris/include/asm/pci.h | 1 +
2 files changed, 1 insertion(+), 23 deletions(-)

diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index a589686d..394c2a73 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -14,29 +14,6 @@ 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, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long prot;
-
- /* Leave vm_pgoff as-is, the PCI space address is the physical
- * address on this platform.
- */
- prot = pgprot_val(vma->vm_page_prot);
- vma->vm_page_prot = __pgprot(prot);
-
- /* Write-combine setting is ignored, it is changed via the mtrr
- * interfaces on this platform.
- */
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
-
resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
resource_size_t size, resource_size_t align)
diff --git a/arch/cris/include/asm/pci.h b/arch/cris/include/asm/pci.h
index 65198cb..6e50533 100644
--- a/arch/cris/include/asm/pci.h
+++ b/arch/cris/include/asm/pci.h
@@ -42,6 +42,7 @@ struct pci_dev;
#define PCI_DMA_BUS_IS_PHYS (1)

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/x86/include/asm/pci.h | 1 +
arch/x86/pci/i386.c | 48 ----------------------------------------------
2 files changed, 1 insertion(+), 48 deletions(-)

diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 734cc94..f513cc2 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -104,6 +104,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);

#define HAVE_PCI_MMAP
#define arch_can_pci_mmap_wc() pat_enabled()
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#ifdef CONFIG_PCI
extern void early_quirks(void);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 8ca5e5d..68499cf 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -406,51 +406,3 @@ void __init pcibios_resource_survey(void)
*/
ioapic_insert_resources();
}
-
-static const struct vm_operations_struct pci_mmap_ops = {
- .access = generic_access_phys,
-};
-
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long prot;
-
- /* I/O space cannot be accessed via normal processor loads and
- * stores on this platform.
- */
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- prot = pgprot_val(vma->vm_page_prot);
-
- /*
- * Return error if pat is not enabled and write_combine is requested.
- * Caller can followup with UC MINUS request and add a WC mtrr if there
- * is a free mtrr slot.
- */
- if (!pat_enabled() && write_combine)
- return -EINVAL;
-
- if (pat_enabled() && write_combine)
- prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
- else if (pat_enabled() || boot_cpu_data.x86 > 3)
- /*
- * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
- * To avoid attribute conflicts, request UC MINUS here
- * as well.
- */
- prot |= cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
-
- vma->vm_page_prot = __pgprot(prot);
-
- if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- vma->vm_ops = &pci_mmap_ops;
-
- return 0;
-}
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:10 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

For a PCI MMIO BAR, phys_mem_access_prot() should always return UC or WC.
And while a mixture of cached and uncached mappings is forbidden, we were
already mixing WC and UC, which is OK. Just do as we're asked.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/ia64/pci/pci.c | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 27020f3..7438e8c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -423,9 +423,6 @@ pci_mmap_page_range (struct pci_dev *dev, int bar,
struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
- unsigned long size = vma->vm_end - vma->vm_start;
- pgprot_t prot;
-
/*
* I/O space cannot be accessed via normal processor loads and
* stores on this platform.
@@ -439,21 +436,10 @@ pci_mmap_page_range (struct pci_dev *dev, int bar,
*/
return -EINVAL;

- prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
- vma->vm_page_prot);
-
- /*
- * If the user requested WC, the kernel uses UC or WC for this region,
- * and the chipset supports WC, we can use WC. Otherwise, we have to
- * use the same attribute the kernel uses.
- */
- if (write_combine &&
- ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC ||
- (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) &&
- efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
+ if (write_combine)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
else
- vma->vm_page_prot = prot;
+ vma->vm_page_prot = pgprot_device(vma->vm_page_prot);

if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:10 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/microblaze/include/asm/pci.h | 7 +--
arch/microblaze/pci/pci-common.c | 99 ++++-----------------------------------
2 files changed, 13 insertions(+), 93 deletions(-)

diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index efd4983..97452c0 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -47,9 +47,10 @@ extern int pci_proc_domain(struct pci_bus *bus);

struct vm_area_struct;

-/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
-#define HAVE_PCI_MMAP 1
-#define arch_can_pci_mmap_io() 1
+/* Tell PCI code what kind of PCI resource mappings we support */
+#define HAVE_PCI_MMAP 1
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
+#define arch_can_pci_mmap_io() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
size_t count);
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 404fb38..69c69f6 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -151,72 +151,22 @@ void pcibios_set_master(struct pci_dev *dev)
}

/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
- * -- paulus.
+ * Platform support for /proc/bus/pci/X/Y mmap()s.
*/

-/*
- * 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)
+int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long io_offset = 0;
- int i, res_bit;
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ resource_size_t ioaddr = pci_resource_start(pdev, bar);

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;
+ return -EINVAL; /* should never happen */

- /* 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;
- }
+ /* Convert to an offset within this PCI controller */
+ ioaddr -= (unsigned long)hose->io_base_virt - _IO_BASE;

- return NULL;
+ vma->vm_pgoff += (ioaddr + hose->io_base_phys) >> PAGE_SHIFT;
+ return 0;
}

/*
@@ -268,37 +218,6 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
return prot;
}

-/*
- * Perform the actual remap of the pages for a PCI device mapping, as
- * appropriate for this architecture. The region in the process to map
- * is described by vm_start and vm_end members of VMA, the base physical
- * address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, int bar, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- 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;
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- 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);
-
- return ret;
-}
-
/* This provides legacy IO read access on a bus */
int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
{
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:12 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

This will need to call into an arch-provided pci_iobar_pfn() function.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
drivers/pci/mmap.c | 11 +++++++----
include/linux/pci.h | 4 ++++
2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/mmap.c b/drivers/pci/mmap.c
index 9ba720b..16e1d70 100644
--- a/drivers/pci/mmap.c
+++ b/drivers/pci/mmap.c
@@ -45,9 +45,6 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
{
unsigned long size;

- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
size = ((pci_resource_len(pdev, bar) - 1) >> PAGE_SHIFT) + 1;
if (vma->vm_pgoff + vma_pages(vma) > size)
return -EINVAL;
@@ -57,7 +54,13 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
else
vma->vm_page_prot = pgprot_device(vma->vm_page_prot);

- vma->vm_pgoff += (pci_resource_start(pdev, bar) >> PAGE_SHIFT);
+ if (mmap_state == pci_mmap_io) {
+ int ret = pci_iobar_pfn(pdev, bar, vma);
+ if (ret)
+ return ret;
+ } else
+ vma->vm_pgoff += (pci_resource_start(pdev, bar) >> PAGE_SHIFT);
+
vma->vm_ops = &pci_phys_vm_ops;

return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index ff1c818..0d40ddd 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1648,8 +1648,12 @@ int pci_mmap_page_range(struct pci_dev *pdev, int bar,
#ifndef arch_can_pci_mmap_wc
#define arch_can_pci_mmap_wc() 0
#endif
+
#ifndef arch_can_pci_mmap_io
#define arch_can_pci_mmap_io() 0
+#define pci_iobar_pfn(pdev, bar, vma) (-EINVAL)
+#else
+int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma);
#endif

#ifndef pci_root_bus_fwnode
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:13 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

These should be uncached, not write-through.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/xtensa/kernel/pci.c | 21 +--------------------
1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index b848cc3..5b73fc2 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -334,25 +334,6 @@ __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
}

/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static __inline__ void
-__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- int prot = pgprot_val(vma->vm_page_prot);
-
- /* Set to write-through */
- prot = (prot & _PAGE_CA_MASK) | _PAGE_CA_WT;
-#if 0
- if (!write_combine)
- prot |= _PAGE_WRITETHRU;
-#endif
- vma->vm_page_prot = __pgprot(prot);
-}
-
-/*
* Perform the actual remap of the pages for a PCI device mapping, as
* appropriate for this architecture. The region in the process to map
* is described by vm_start and vm_end members of VMA, the base physical
@@ -372,7 +353,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
if (ret < 0)
return ret;

- __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+ vma->vm_page_prot = pgprot_device(vma->vm_page_prot);

ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start,vma->vm_page_prot);
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:33 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

In the PCI_MMAP_PROCFS case when the address being passed by the user
is a 'user visible' resource address based on the bus window, and not
the actual contents of the resource, that's what we need to be checking
it against.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
Cc: sta...@vger.kernel.org
---
drivers/pci/pci-sysfs.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 25d010d..7ac258f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -985,15 +985,19 @@ void pci_remove_legacy_files(struct pci_bus *b)
int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
{
- unsigned long nr, start, size, pci_start;
+ unsigned long nr, start, size;
+ resource_size_t pci_start = 0, pci_end;

if (pci_resource_len(pdev, resno) == 0)
return 0;
nr = vma_pages(vma);
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 (mmap_api == PCI_MMAP_PROCFS) {
+ pci_resource_to_user(pdev, resno, &pdev->resource[resno],
+ &pci_start, &pci_end);
+ pci_start >>= PAGE_SHIFT;
+ }
if (start >= pci_start && start < pci_start + size &&
start + nr <= pci_start + size)
return 1;
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:30:44 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

This is relatively esoteric, and knowing that we don't have it makes
life easier in some cases rather than just an eventual -EINVAL from
pci_mmap_page_range().

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Documentation/filesystems/sysfs-pci.txt | 3 ++-
arch/microblaze/include/asm/pci.h | 3 ++-
arch/powerpc/include/asm/pci.h | 1 +
arch/sparc/include/asm/pci_64.h | 1 +
arch/xtensa/include/asm/pci.h | 3 ++-
drivers/pci/pci-sysfs.c | 13 ++++++++-----
drivers/pci/proc.c | 11 +++++++----
include/linux/pci.h | 3 +++
8 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 25b7f1c..46b95d8 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -119,7 +119,8 @@ useful return codes should be provided.

Platforms which support write-combining maps of PCI resources must define
arch_can_pci_mmap_wc() which shall evaluate to non-zero at runtime when
-write-combining is permitted.
+write-combining is permitted. Platforms which support maps of I/O resources
+define arch_can_pci_mmap_io() similarly.

Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms
wishing to support legacy functionality should define it and provide
diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index ab381d2..efd4983 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
@@ -48,7 +48,8 @@ extern int pci_proc_domain(struct pci_bus *bus);
struct vm_area_struct;

/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
-#define HAVE_PCI_MMAP 1
+#define HAVE_PCI_MMAP 1
+#define arch_can_pci_mmap_io() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
size_t count);
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 55887d1..c8975da 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -80,6 +80,7 @@ struct vm_area_struct;

/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() and it does WC */
#define HAVE_PCI_MMAP 1
+#define arch_can_pci_mmap_io() 1
#define arch_can_pci_mmap_wc() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index 516fda7..b957ca5 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -42,6 +42,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
/* Platform support for /proc/bus/pci/X/Y mmap()s. */

#define HAVE_PCI_MMAP
+#define arch_can_pci_mmap_io() 1
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
#define get_pci_unmapped_area get_fb_unmapped_area

diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index bb5510b..e4f366a 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -47,7 +47,8 @@ struct pci_dev;
#define PCI_DMA_BUS_IS_PHYS (1)

/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
-#define HAVE_PCI_MMAP 1
+#define HAVE_PCI_MMAP 1
+#define arch_can_pci_mmap_io() 1

#endif /* __KERNEL__ */

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7d494bd..cb04bc2 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1174,11 +1174,14 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
} else {
pdev->res_attr[num] = res_attr;
sprintf(res_attr_name, "resource%d", num);
- res_attr->mmap = pci_mmap_resource_uc;
- }
- if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
- res_attr->read = pci_read_resource_io;
- res_attr->write = pci_write_resource_io;
+ if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
+ res_attr->read = pci_read_resource_io;
+ res_attr->write = pci_write_resource_io;
+ if (arch_can_pci_mmap_io())
+ res_attr->mmap = pci_mmap_resource_uc;
+ } else {
+ res_attr->mmap = pci_mmap_resource_uc;
+ }
}
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = S_IRUSR | S_IWUSR;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index a2aa58a..45e5cf7 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -202,6 +202,8 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,

#ifdef HAVE_PCI_MMAP
case PCIIOC_MMAP_IS_IO:
+ if (!arch_can_pci_mmap_io())
+ return -EINVAL;
fpriv->mmap_state = pci_mmap_io;
break;

@@ -232,15 +234,16 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
struct pci_dev *dev = PDE_DATA(file_inode(file));
struct pci_filp_private *fpriv = file->private_data;
- int i, ret, write_combine = 0, res_bit;
+ int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;

if (!capable(CAP_SYS_RAWIO))
return -EPERM;

- if (fpriv->mmap_state == pci_mmap_io)
+ if (fpriv->mmap_state == pci_mmap_io) {
+ if (!arch_can_pci_mmap_io())
+ return -EINVAL;
res_bit = IORESOURCE_IO;
- else
- res_bit = IORESOURCE_MEM;
+ }

/* Make sure the caller is mapping a real resource for this device */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
diff --git a/include/linux/pci.h b/include/linux/pci.h
index e7bb4b62..590cfcf 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1636,6 +1636,9 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
#ifndef arch_can_pci_mmap_wc
#define arch_can_pci_mmap_wc() 0
#endif
+#ifndef arch_can_pci_mmap_io
+#define arch_can_pci_mmap_io() 0
+#endif

#ifndef pci_root_bus_fwnode
#define pci_root_bus_fwnode(bus) NULL
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:05 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Don't match MMIO maps with I/O BARs and vice versa.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
Cc: sta...@vger.kernel.org
---
drivers/pci/proc.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index f82710a..62a0c3e 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -231,14 +231,20 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
struct pci_dev *dev = PDE_DATA(file_inode(file));
struct pci_filp_private *fpriv = file->private_data;
- int i, ret, write_combine;
+ int i, ret, write_combine, res_bit;

if (!capable(CAP_SYS_RAWIO))
return -EPERM;

+ if (fpriv->mmap_state == pci_mmap_io)
+ res_bit = IORESOURCE_IO;
+ else
+ res_bit = IORESOURCE_MEM;
+
/* Make sure the caller is mapping a real resource for this device */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
- if (pci_mmap_fits(dev, i, vma, PCI_MMAP_PROCFS))
+ if (dev->resource[i].flags & res_bit &&
+ pci_mmap_fits(dev, i, vma, PCI_MMAP_PROCFS))
break;
}

--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:05 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

We store the pointer, and then on *every* use of it we loop over the
device's resources to find out the index. That's kind of silly.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
drivers/pci/pci-sysfs.c | 38 ++++++++++++++------------------------
1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index cb04bc2..534844d 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1017,26 +1017,20 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
struct vm_area_struct *vma, int write_combine)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
- struct resource *res = attr->private;
+ int bar = (unsigned long)attr->private;
enum pci_mmap_state mmap_type;
resource_size_t start, end;
- int i;
-
- for (i = 0; i < PCI_ROM_RESOURCE; i++)
- if (res == &pdev->resource[i])
- break;
- if (i >= PCI_ROM_RESOURCE)
- return -ENODEV;
+ struct resource *res = &pdev->resource[bar];

if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
return -EINVAL;

- if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) {
+ if (!pci_mmap_fits(pdev, bar, vma, 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,
- (u64)pci_resource_start(pdev, i),
- (u64)pci_resource_len(pdev, i));
+ pci_name(pdev), bar,
+ (u64)pci_resource_start(pdev, bar),
+ (u64)pci_resource_len(pdev, bar));
return -EINVAL;
}

@@ -1044,7 +1038,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
* 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);
+ pci_resource_to_user(pdev, bar, 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);
@@ -1069,22 +1063,18 @@ static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj,
loff_t off, size_t count, bool write)
{
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
- struct resource *res = attr->private;
+ int bar = (unsigned long)attr->private;
+ struct resource *res;
unsigned long port = off;
- int i;

- for (i = 0; i < PCI_ROM_RESOURCE; i++)
- if (res == &pdev->resource[i])
- break;
- if (i >= PCI_ROM_RESOURCE)
- return -ENODEV;
+ res = &pdev->resource[bar];

- port += pci_resource_start(pdev, i);
+ port += pci_resource_start(pdev, bar);

- if (port > pci_resource_end(pdev, i))
+ if (port > pci_resource_end(pdev, bar))
return 0;

- if (port + count - 1 > pci_resource_end(pdev, i))
+ if (port + count - 1 > pci_resource_end(pdev, bar))
return -EINVAL;

switch (count) {
@@ -1186,7 +1176,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = S_IRUSR | S_IWUSR;
res_attr->size = pci_resource_len(pdev, num);
- res_attr->private = &pdev->resource[num];
+ res_attr->private = (void *)(unsigned long)num;
retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
if (retval)
kfree(res_attr);
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:05 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

This was setting vma->vm_flags |= VM_LOCKED. Not sure why...

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/mn10300/include/asm/pci.h | 1 +
arch/mn10300/unit-asb2305/pci-asb2305.c | 24 ------------------------
2 files changed, 1 insertion(+), 24 deletions(-)

diff --git a/arch/mn10300/include/asm/pci.h b/arch/mn10300/include/asm/pci.h
index 082b6de..d276549 100644
--- a/arch/mn10300/include/asm/pci.h
+++ b/arch/mn10300/include/asm/pci.h
@@ -74,6 +74,7 @@ static inline int pci_controller_num(struct pci_dev *dev)
}

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c
index 4abbbd5..e0f4617 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.c
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.c
@@ -210,27 +210,3 @@ void __init pcibios_resource_survey(void)
pcibios_allocate_resources(0);
pcibios_allocate_resources(1);
}
-
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long prot;
-
- /* Leave vm_pgoff as-is, the PCI space address is the physical
- * address on this platform.
- */
- vma->vm_flags |= VM_LOCKED;
-
- prot = pgprot_val(vma->vm_page_prot);
- prot &= ~_PAGE_CACHE;
- vma->vm_page_prot = __pgprot(prot);
-
- /* Write-combine setting is ignored */
- if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-

David Woodhouse

unread,
Apr 12, 2017, 8:40:05 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/xtensa/include/asm/pci.h | 7 ++--
arch/xtensa/kernel/pci.c | 94 ++++---------------------------------------
2 files changed, 12 insertions(+), 89 deletions(-)

diff --git a/arch/xtensa/include/asm/pci.h b/arch/xtensa/include/asm/pci.h
index e4f366a..0ddb411 100644
--- a/arch/xtensa/include/asm/pci.h
+++ b/arch/xtensa/include/asm/pci.h
@@ -46,9 +46,10 @@ struct pci_dev;

#define PCI_DMA_BUS_IS_PHYS (1)

-/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
-#define HAVE_PCI_MMAP 1
-#define arch_can_pci_mmap_io() 1
+/* Tell PCI code what kind of PCI resource mappings we support */
+#define HAVE_PCI_MMAP 1
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
+#define arch_can_pci_mmap_io() 1

#endif /* __KERNEL__ */

diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 903963e..8f11b6d 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -47,7 +47,6 @@
* pcibios_align_resource
* pcibios_fixup_bus
* pci_bus_add_device
- * pci_mmap_page_range
*/

struct pci_controller* pci_ctrl_head;
@@ -266,98 +265,21 @@ pci_controller_num(struct pci_dev *dev)
#endif /* CONFIG_PROC_FS */

/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
+ * Platform support for /proc/bus/pci/X/Y mmap()s.
* -- paulus.
*/

-/*
- * 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 __inline__ int
-__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
+int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
{
- struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long io_offset = 0;
- int i, res_bit;
+ struct pci_controller *pci_ctrl = (struct pci_controller*) pdev->sysdata;
+ resource_size_t ioaddr = pci_resource_start(pdev, bar);

if (pci_ctrl == 0)
return -EINVAL; /* should never happen */

- /* If memory, add on the PCI bridge address offset */
- if (mmap_state == pci_mmap_mem) {
- res_bit = IORESOURCE_MEM;
- } else {
- io_offset = (unsigned long)pci_ctrl->io_space.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 += pci_ctrl->io_space.start - io_offset;
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- return 0;
- }
-
- return -EINVAL;
-}
+ /* Convert to an offset within this PCI controller */
+ ioaddr -= (unsigned long)pci_ctrl->io_space.base;

-/*
- * Perform the actual remap of the pages for a PCI device mapping, as
- * appropriate for this architecture. The region in the process to map
- * is described by vm_start and vm_end members of VMA, the base physical
- * address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
-{
- int ret;
-
- ret = __pci_mmap_make_offset(dev, vma, mmap_state);
- if (ret < 0)
- return ret;
-
- vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
-
- ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,vma->vm_page_prot);
-
- return ret;
+ vma->vm_pgoff += (ioaddr + pci_ctrl->io_space.start) >> PAGE_SHIFT;
+ return 0;
}
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:05 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Now that we eliminated the different behaviour in separately-reviewable
commits, we can switch IA64 to the generic implementation.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/ia64/include/asm/pci.h | 1 +
arch/ia64/pci/pci.c | 30 ------------------------------
2 files changed, 1 insertion(+), 30 deletions(-)

diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index fc60b3d..6459f2d 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -51,6 +51,7 @@ extern unsigned long ia64_max_iommu_merge_mask;
#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL)

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define arch_can_pci_mmap_wc() 1

#define HAVE_PCI_LEGACY
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 7438e8c..4068bde 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -418,36 +418,6 @@ pcibios_align_resource (void *data, const struct resource *res,
return res->start;
}

-int
-pci_mmap_page_range (struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- /*
- * I/O space cannot be accessed via normal processor loads and
- * stores on this platform.
- */
- if (mmap_state == pci_mmap_io)
- /*
- * XXX we could relax this for I/O spaces for which ACPI
- * indicates that the space is 1-to-1 mapped. But at the
- * moment, we don't support multiple PCI address spaces and
- * the legacy I/O space is not 1-to-1 mapped, so this is moot.
- */
- return -EINVAL;
-
- if (write_combine)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
-
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
-
/**
* ia64_pci_get_legacy_mem - generic legacy mem routine
* @bus: bus to get legacy memory base address for
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/unicore32/include/asm/pci.h | 1 +
arch/unicore32/kernel/pci.c | 24 ------------------------
2 files changed, 1 insertion(+), 24 deletions(-)

diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
index a5129086..ac5acdf 100644
--- a/arch/unicore32/include/asm/pci.h
+++ b/arch/unicore32/include/asm/pci.h
@@ -17,6 +17,7 @@
#include <mach/hardware.h> /* for PCIBIOS_MIN_* */

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */
#endif
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index 1b43885..1053bca 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -356,27 +356,3 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
}
return 0;
}
-
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long phys;
-
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- phys = vma->vm_pgoff;
-
- /*
- * Mark this as IO
- */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (remap_pfn_range(vma, vma->vm_start, phys,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:06 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

In all cases we know which BAR it is. Passing it in means that arch code
(or generic code; watch this space) won't have to go looking for it again.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/arm/kernel/bios32.c | 3 ++-
arch/cris/arch-v32/drivers/pci/bios.c | 3 ++-
arch/ia64/pci/pci.c | 3 ++-
arch/microblaze/pci/pci-common.c | 2 +-
arch/mips/pci/pci.c | 3 ++-
arch/mn10300/unit-asb2305/pci-asb2305.c | 3 ++-
arch/parisc/kernel/pci.c | 3 ++-
arch/powerpc/kernel/pci-common.c | 3 ++-
arch/sh/drivers/pci/pci.c | 3 ++-
arch/sparc/kernel/pci.c | 6 +++---
arch/unicore32/kernel/pci.c | 3 ++-
arch/x86/pci/i386.c | 3 ++-
arch/xtensa/kernel/pci.c | 3 ++-
drivers/pci/pci-sysfs.c | 2 +-
drivers/pci/proc.c | 2 +-
include/linux/pci.h | 3 ++-
16 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 2f0e077..a4fc3f4 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -597,7 +597,8 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}

-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+int pci_mmap_page_range(struct pci_dev *dev, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
if (mmap_state == pci_mmap_io)
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 212266a..a589686d 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 8f6ac2f..053c688 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long size = vma->vm_end - vma->vm_start;
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 13bc932..404fb38 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -278,7 +278,7 @@ 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, int bar, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
resource_size_t offset =
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index f6325fa..f189502 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -58,7 +58,8 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
*end = rsrc->start + size;
}

-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+int pci_mmap_page_range(struct pci_dev *dev, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c
index b7ab837..4abbbd5 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.c
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.c
@@ -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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 0903c6a..6538775 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index ffda24a..6dda4a2 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -513,7 +513,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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
resource_size_t offset =
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 84563e3..c8b36b7 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -269,7 +269,8 @@ void __ref 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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
/*
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 015e55a..7eceaa1 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -862,9 +862,9 @@ 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,
- enum pci_mmap_state mmap_state,
- int write_combine)
+int pci_mmap_page_range(struct pci_dev *dev, int bar,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
{
int ret;

diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index 62137d1..1b43885 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -357,7 +357,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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long phys;
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 0a9f2ca..8ca5e5d 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
unsigned long prot;
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 5b73fc2..903963e 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -343,7 +343,8 @@ __pci_mmap_make_offset(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, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine)
{
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 534844d..bfd9efe 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1041,7 +1041,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
pci_resource_to_user(pdev, bar, 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, bar, vma, mmap_type, write_combine);
}

static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 45e5cf7..098360d 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -262,7 +262,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
else
return -EINVAL;
}
- ret = pci_mmap_page_range(dev, vma,
+ ret = pci_mmap_page_range(dev, i, vma,
fpriv->mmap_state, write_combine);
if (ret < 0)
return ret;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 590cfcf..7173a67 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1630,7 +1630,8 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
* Architectures provide this function if they set HAVE_PCI_MMAP, and
* it accepts the 'write_combine' argument when arch_can_pci_mmap_wc()
* evaluates to nonzero. */
-int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+int pci_mmap_page_range(struct pci_dev *pdev, int bar,
+ struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);

#ifndef arch_can_pci_mmap_wc
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:07 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/mips/include/asm/pci.h | 2 +-
arch/mips/pci/pci.c | 25 -------------------------
2 files changed, 1 insertion(+), 26 deletions(-)

diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 3141e2a..1000c1b 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -110,7 +110,7 @@ extern unsigned long PCIBIOS_MIN_MEM;
extern void pcibios_set_master(struct pci_dev *dev);

#define HAVE_PCI_MMAP
-
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define HAVE_ARCH_PCI_RESOURCE_TO_USER

/*
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index f189502..bd67ac7 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -57,28 +57,3 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
*start = fixup_bigphys_addr(rsrc->start, size);
*end = rsrc->start + size;
}
-
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- unsigned long prot;
-
- /*
- * I/O space can be accessed via normal processor loads and stores on
- * this platform but for now we elect not to do this and portable
- * drivers should not do this anyway.
- */
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- /*
- * Ignore write-combine; for now only return uncached mappings.
- */
- prot = pgprot_val(vma->vm_page_prot);
- prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
- vma->vm_page_prot = __pgprot(prot);
-
- return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:10 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Most of the almost-identical versions of pci_mmap_page_range() silently
ignore the 'write_combine' argument and give uncached mappings.

Yet we allow the PCIIOC_WRITE_COMBINE ioctl in /proc/bus/pci, expose the
'resourceX_wc' file in sysfs, and allow an attempted mapping to apparently
succeed.

To fix this, introduce a macro arch_can_pci_mmap_wc() which indicates
whether the platform can do a write-combining mapping. On x86 this ends
up being pat_enabled(), while the few other platforms that support it
can just set it to a literal '1'.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Documentation/filesystems/sysfs-pci.txt | 4 ++++
arch/ia64/include/asm/pci.h | 2 ++
arch/powerpc/include/asm/pci.h | 5 +++--
arch/x86/include/asm/pci.h | 2 ++
drivers/pci/pci-sysfs.c | 4 ++--
drivers/pci/proc.c | 15 ++++++++-------
include/linux/pci.h | 4 ++++
7 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 6ea1ced..25b7f1c 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -117,6 +117,10 @@ code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function.
Platforms are free to only support subsets of the mmap functionality, but
useful return codes should be provided.

+Platforms which support write-combining maps of PCI resources must define
+arch_can_pci_mmap_wc() which shall evaluate to non-zero at runtime when
+write-combining is permitted.
+
Legacy resources are protected by the HAVE_PCI_LEGACY define. Platforms
wishing to support legacy functionality should define it and provide
pci_legacy_read, pci_legacy_write and pci_mmap_legacy_page_range functions.
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index c0835b0..6283758 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -51,6 +51,8 @@ extern unsigned long ia64_max_iommu_merge_mask;
#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL)

#define HAVE_PCI_MMAP
+#define arch_can_pci_mmap_wc() 1
+
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
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 93eded8..b5b68c6 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -81,8 +81,9 @@ struct vm_area_struct;
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
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() and it does WC */
+#define HAVE_PCI_MMAP 1
+#define arch_can_pci_mmap_wc() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
size_t count);
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 1411dbe..f6e22c2 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -7,6 +7,7 @@
#include <linux/string.h>
#include <linux/scatterlist.h>
#include <asm/io.h>
+#include <asm/pat.h>
#include <asm/x86_init.h>

#ifdef __KERNEL__
@@ -102,6 +103,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);


#define HAVE_PCI_MMAP
+#define arch_can_pci_mmap_wc() pat_enabled()
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state,
int write_combine);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 7ac258f..7d494bd 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1211,9 +1211,9 @@ static int pci_create_resource_files(struct pci_dev *pdev)

retval = pci_create_attr(pdev, i, 0);
/* for prefetchable resources, create a WC mappable file */
- if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH)
+ if (!retval && arch_can_pci_mmap_wc() &&
+ pdev->resource[i].flags & IORESOURCE_PREFETCH)
retval = pci_create_attr(pdev, i, 1);
-
if (retval) {
pci_remove_resource_files(pdev);
return retval;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index dc8912e..a2aa58a 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -210,14 +210,15 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
break;

case PCIIOC_WRITE_COMBINE:
- if (arg)
- fpriv->write_combine = 1;
- else
- fpriv->write_combine = 0;
- break;
-
+ if (arch_can_pci_mmap_wc()) {
+ if (arg)
+ fpriv->write_combine = 1;
+ else
+ fpriv->write_combine = 0;
+ break;
+ }
+ /* If arch decided it can't, fall through... */
#endif /* HAVE_PCI_MMAP */
-
default:
ret = -EINVAL;
break;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index eb3da1a..e614fb4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1626,6 +1626,10 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }

#include <asm/pci.h>

+#ifndef arch_can_pci_mmap_wc
+#define arch_can_pci_mmap_wc() 0
+#endif
+
#ifndef pci_root_bus_fwnode
#define pci_root_bus_fwnode(bus) NULL
#endif
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:10 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Starting to leave behind the legacy of the pci_mmap_page_range()
interface which takes "user-visible" BAR addresses. This takes just the
resource and offset.

For now, both APIs coexist and depending on the platform, one is
implemented as a wrapper around the other.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
Documentation/filesystems/sysfs-pci.txt | 10 ++--
arch/arm64/include/asm/pci.h | 2 +
drivers/pci/Makefile | 2 +-
drivers/pci/mmap.c | 84 +++++++++++++++++++++++++++++++++
drivers/pci/pci-sysfs.c | 13 ++---
drivers/pci/pci.h | 4 +-
include/linux/pci.h | 19 ++++++--
7 files changed, 114 insertions(+), 20 deletions(-)
create mode 100644 drivers/pci/mmap.c

diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt
index 46b95d8..06f1d64 100644
--- a/Documentation/filesystems/sysfs-pci.txt
+++ b/Documentation/filesystems/sysfs-pci.txt
@@ -113,9 +113,13 @@ Supporting PCI access on new platforms
--------------------------------------

In order to support PCI resource mapping as described above, Linux platform
-code must define HAVE_PCI_MMAP and provide a pci_mmap_page_range function.
-Platforms are free to only support subsets of the mmap functionality, but
-useful return codes should be provided.
+code should ideally define ARCH_GENERIC_PCI_MMAP_RESOURCE and use the generic
+implementation of that functionality. To support the historical interface of
+mmap() through files in /proc/bus/pci, platforms may also set HAVE_PCI_MMAP.
+
+Alternatively, platforms which set HAVE_PCI_MMAP may provide their own
+implementation of pci_mmap_page_range() instead of defining
+ARCH_GENERIC_PCI_MMAP_RESOURCE.

Platforms which support write-combining maps of PCI resources must define
arch_can_pci_mmap_wc() which shall evaluate to non-zero at runtime when
diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h
index b9a7ba9..1fc1974 100644
--- a/arch/arm64/include/asm/pci.h
+++ b/arch/arm64/include/asm/pci.h
@@ -22,6 +22,8 @@
*/
#define PCI_DMA_BUS_IS_PHYS (0)

+#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
+
extern int isa_dma_bridge_buggy;

#ifdef CONFIG_PCI
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 8db5079..3d40e41 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,7 @@

obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o
+ irq.o vpd.o setup-bus.o vc.o mmap.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o

diff --git a/drivers/pci/mmap.c b/drivers/pci/mmap.c
new file mode 100644
index 0000000..9ba720b
--- /dev/null
+++ b/drivers/pci/mmap.c
@@ -0,0 +1,84 @@
+/*
+ * mmap.c — generic PCI resource mmap helper
+ *
+ * Copyright © 2017 Amazon.com, Inc. or its affiliates.
+ *
+ * Author: David Woodhouse <dw...@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+
+#ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
+/* Modern setup: generic pci_mmap_resource_range(), and implement the legacy
+ * pci_mmap_page_range() (if needed) as a wrapper round it. */
+
+#ifdef HAVE_PCI_MMAP
+int pci_mmap_page_range(struct pci_dev *pdev, int bar,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ /* Adjust vm_pgoff to be the offset within the resource */
+ resource_size_t start, end;
+
+ pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end);
+ vma->vm_pgoff -= start >> PAGE_SHIFT;
+ return pci_mmap_resource_range(pdev, bar, vma, mmap_state, write_combine);
+}
+#endif
+
+static const struct vm_operations_struct pci_phys_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys,
+#endif
+};
+
+int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ unsigned long size;
+
+ if (mmap_state == pci_mmap_io)
+ return -EINVAL;
+
+ size = ((pci_resource_len(pdev, bar) - 1) >> PAGE_SHIFT) + 1;
+ if (vma->vm_pgoff + vma_pages(vma) > size)
+ return -EINVAL;
+
+ if (write_combine)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
+
+ vma->vm_pgoff += (pci_resource_start(pdev, bar) >> PAGE_SHIFT);
+ vma->vm_ops = &pci_phys_vm_ops;
+
+ return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */
+/* Legacy setup: Impement pci_mmap_resource_range() as a wrapper around
+ the architecture's pci_mmap_page_range(), converting to "user visible"
+ addresses as necessary. */
+int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ resource_size_t start, end;
+ /* 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, bar, &pdev->resource[bar], &start, &end);
+ vma->vm_pgoff += start >> PAGE_SHIFT;
+ return pci_mmap_page_range(pdev, bar, vma, mmap_state, write_combine);
+}
+#endif
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index bfd9efe..10feb98 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -980,7 +980,7 @@ void pci_remove_legacy_files(struct pci_bus *b)
}
#endif /* HAVE_PCI_LEGACY */

-#ifdef HAVE_PCI_MMAP
+#if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)

int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
@@ -1019,7 +1019,6 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
int bar = (unsigned long)attr->private;
enum pci_mmap_state mmap_type;
- resource_size_t start, end;
struct resource *res = &pdev->resource[bar];

if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
@@ -1033,15 +1032,9 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
(u64)pci_resource_len(pdev, bar));
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, bar, 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, bar, vma, mmap_type, write_combine);
+
+ return pci_mmap_resource_range(pdev, bar, vma, mmap_type, write_combine);
}

static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 8dd38e6..8e5ca2d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -21,14 +21,14 @@ void pci_create_firmware_label_files(struct pci_dev *pdev);
void pci_remove_firmware_label_files(struct pci_dev *pdev);
#endif
void pci_cleanup_rom(struct pci_dev *dev);
-#ifdef HAVE_PCI_MMAP
+
enum pci_mmap_api {
PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
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);
-#endif
+
int pci_probe_reset_function(struct pci_dev *dev);

/**
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7173a67..ff1c818 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1626,10 +1626,21 @@ static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }

#include <asm/pci.h>

-/* Map a range of PCI memory or I/O space for a device into user space.
- * Architectures provide this function if they set HAVE_PCI_MMAP, and
- * it accepts the 'write_combine' argument when arch_can_pci_mmap_wc()
- * evaluates to nonzero. */
+/* These two functions provide almost identical functionality. Depennding
+ * on the architecture, one will be implemented as a wrapper aroudn the
+ * other (in drivers/pci/mmap.c).
+ *
+ * pci_mmap_resource_range() maps a specific BAR, and vm->vm_pgoff
+ * is expected to be an offset within that region.
+ *
+ * pci_mmap_page_range() is the legacy architecture-specific interface,
+ * which accepts a "user visible" resource address converted by
+ * pci_resource_to_user(), as used in the legacy mmap() interface in
+ * /proc/bus/pci/.
+ */
+int pci_mmap_resource_range(struct pci_dev *dev, int bar,
+ struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine);
int pci_mmap_page_range(struct pci_dev *pdev, int bar,
struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:12 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/sparc/include/asm/pci_64.h | 1 +
arch/sparc/kernel/pci.c | 155 ----------------------------------------
2 files changed, 1 insertion(+), 155 deletions(-)

diff --git a/arch/sparc/include/asm/pci_64.h b/arch/sparc/include/asm/pci_64.h
index b957ca5..b8206d5 100644
--- a/arch/sparc/include/asm/pci_64.h
+++ b/arch/sparc/include/asm/pci_64.h
@@ -42,6 +42,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
/* Platform support for /proc/bus/pci/X/Y mmap()s. */

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define arch_can_pci_mmap_io() 1
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
#define get_pci_unmapped_area get_fb_unmapped_area
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 7eceaa1..56a9a9f 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -730,161 +730,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return 0;
}

-/* Platform support for /proc/bus/pci/X/Y mmap()s. */
-
-/* If the user uses a host-bridge as the PCI device, he may use
- * this to perform a raw mmap() of the I/O or MEM space behind
- * that controller.
- *
- * This can be useful for execution of x86 PCI bios initialization code
- * on a PCI card, like the xfree86 int10 stuff does.
- */
-static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long space_size, user_offset, user_size;
-
- if (mmap_state == pci_mmap_io) {
- space_size = resource_size(&pbm->io_space);
- } else {
- space_size = resource_size(&pbm->mem_space);
- }
-
- /* Make sure the request is in range. */
- user_offset = vma->vm_pgoff << PAGE_SHIFT;
- user_size = vma->vm_end - vma->vm_start;
-
- if (user_offset >= space_size ||
- (user_offset + user_size) > space_size)
- return -EINVAL;
-
- if (mmap_state == pci_mmap_io) {
- vma->vm_pgoff = (pbm->io_space.start +
- user_offset) >> PAGE_SHIFT;
- } else {
- vma->vm_pgoff = (pbm->mem_space.start +
- user_offset) >> PAGE_SHIFT;
- }
-
- return 0;
-}
-
-/* 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 int __pci_mmap_make_offset(struct pci_dev *pdev,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- unsigned long user_paddr, user_size;
- int i, err;
-
- /* First compute the physical address in vma->vm_pgoff,
- * making sure the user offset is within range in the
- * appropriate PCI space.
- */
- err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
- if (err)
- return err;
-
- /* If this is a mapping on a host bridge, any address
- * is OK.
- */
- if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
- return err;
-
- /* Otherwise make sure it's in the range for one of the
- * device's resources.
- */
- user_paddr = vma->vm_pgoff << PAGE_SHIFT;
- user_size = vma->vm_end - vma->vm_start;
-
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &pdev->resource[i];
- resource_size_t aligned_end;
-
- /* Active? */
- if (!rp->flags)
- continue;
-
- /* Same type? */
- if (i == PCI_ROM_RESOURCE) {
- if (mmap_state != pci_mmap_mem)
- continue;
- } else {
- if ((mmap_state == pci_mmap_io &&
- (rp->flags & IORESOURCE_IO) == 0) ||
- (mmap_state == pci_mmap_mem &&
- (rp->flags & IORESOURCE_MEM) == 0))
- continue;
- }
-
- /* Align the resource end to the next page address.
- * PAGE_SIZE intentionally added instead of (PAGE_SIZE - 1),
- * because actually we need the address of the next byte
- * after rp->end.
- */
- aligned_end = (rp->end + PAGE_SIZE) & PAGE_MASK;
-
- if ((rp->start <= user_paddr) &&
- (user_paddr + user_size) <= aligned_end)
- break;
- }
-
- if (i > PCI_ROM_RESOURCE)
- return -EINVAL;
-
- return 0;
-}
-
-/* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state)
-{
- /* Our io_remap_pfn_range takes care of this, do nothing. */
-}
-
-/* Perform the actual remap of the pages for a PCI device mapping, as appropriate
- * for this architecture. The region in the process to map is described by vm_start
- * and vm_end members of VMA, the base physical address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- int ret;
-
- ret = __pci_mmap_make_offset(dev, vma, mmap_state);
- if (ret < 0)
- return ret;
-
- __pci_mmap_set_pgprot(dev, vma, mmap_state);
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- ret = io_remap_pfn_range(vma, vma->vm_start,
- vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
- if (ret)
- return ret;
-
- return 0;
-}
-
#ifdef CONFIG_NUMA
int pcibus_to_node(struct pci_bus *pbus)
{
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:12 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

The /proc/bus/pci mmap interface allows the user to specify whether they
want WC or not. Don't let them do so on non-prefetchable BARs.

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
Cc: sta...@vger.kernel.org
---
drivers/pci/proc.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 62a0c3e..dc8912e 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -231,7 +231,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
struct pci_dev *dev = PDE_DATA(file_inode(file));
struct pci_filp_private *fpriv = file->private_data;
- int i, ret, write_combine, res_bit;
+ int i, ret, write_combine = 0, res_bit;

if (!capable(CAP_SYS_RAWIO))
return -EPERM;
@@ -251,10 +251,13 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
if (i >= PCI_ROM_RESOURCE)
return -ENODEV;

- if (fpriv->mmap_state == pci_mmap_mem)
- write_combine = fpriv->write_combine;
- else
- write_combine = 0;
+ if (fpriv->mmap_state == pci_mmap_mem &&
+ fpriv->write_combine) {
+ if (dev->resource[i].flags & IORESOURCE_PREFETCH)
+ write_combine = 1;
+ else
+ return -EINVAL;
+ }
ret = pci_mmap_page_range(dev, vma,
fpriv->mmap_state, write_combine);
if (ret < 0)
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:12 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/powerpc/include/asm/pci.h | 9 ++--
arch/powerpc/kernel/pci-common.c | 106 ++++-----------------------------------
2 files changed, 15 insertions(+), 100 deletions(-)

diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index c8975da..edd5b0d 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -78,10 +78,11 @@ extern int pci_proc_domain(struct pci_bus *bus);

struct vm_area_struct;

-/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() and it does WC */
-#define HAVE_PCI_MMAP 1
-#define arch_can_pci_mmap_io() 1
-#define arch_can_pci_mmap_wc() 1
+/* Tell PCI code what kind of PCI resource mappings we support */
+#define HAVE_PCI_MMAP 1
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1
+#define arch_can_pci_mmap_io() 1
+#define arch_can_pci_mmap_wc() 1

extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
size_t count);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 6dda4a2..17b5e31 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -385,72 +385,22 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
}

/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
+ * Platform support for /proc/bus/pci/X/Y mmap()s.
* -- paulus.
*/
-
-/*
- * 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)
+int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long io_offset = 0;
- int i, res_bit;
-
- if (hose == NULL)
- 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;
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+ resource_size_t ioaddr = pci_resource_start(pdev, bar);

- /* 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;
+ if (!hose)
+ return -EINVAL;

- /* found it! construct the final physical address */
- if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - io_offset;
- return rp;
- }
+ /* Convert to an offset within this PCI controller */
+ ioaddr -= (unsigned long)hose->io_base_virt - _IO_BASE;

- return NULL;
+ vma->vm_pgoff += (ioaddr + hose->io_base_phys) >> PAGE_SHIFT;
+ return 0;
}

/*
@@ -502,42 +452,6 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
return prot;
}

-
-/*
- * Perform the actual remap of the pages for a PCI device mapping, as
- * appropriate for this architecture. The region in the process to map
- * is described by vm_start and vm_end members of VMA, the base physical
- * address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- 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;
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- if (write_combine)
- vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot);
- else
- 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);
-
- return ret;
-}
-
/* This provides legacy IO read access on a bus */
int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
{
--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:26 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/sh/drivers/pci/pci.c | 22 ----------------------
arch/sh/include/asm/pci.h | 1 +
2 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index c8b36b7..c99ee28 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -269,28 +269,6 @@ void __ref pcibios_report_status(unsigned int status_mask, int warn)
}
}

-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- /*
- * I/O space can be accessed via normal processor loads and stores on
- * this platform but for now we elect not to do this and portable
- * drivers should not do this anyway.
- */
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- /*
- * Ignore write-combine; for now only return uncached mappings.
- */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-}
-
#ifndef CONFIG_GENERIC_IOMAP

void __iomem *__pci_ioport_map(struct pci_dev *dev,
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h
index 46abbc9..17fa69b 100644
--- a/arch/sh/include/asm/pci.h
+++ b/arch/sh/include/asm/pci.h
@@ -66,6 +66,7 @@ extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM;
struct pci_dev;

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

extern void pcibios_set_master(struct pci_dev *dev);

--
2.9.3

David Woodhouse

unread,
Apr 12, 2017, 8:40:28 AM4/12/17
to
From: David Woodhouse <dw...@amazon.co.uk>

Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
---
arch/arm/include/asm/pci.h | 1 +
arch/arm/kernel/bios32.c | 20 --------------------
2 files changed, 1 insertion(+), 20 deletions(-)

diff --git a/arch/arm/include/asm/pci.h b/arch/arm/include/asm/pci.h
index 51118a0..396c92b 100644
--- a/arch/arm/include/asm/pci.h
+++ b/arch/arm/include/asm/pci.h
@@ -29,6 +29,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
#define PCI_DMA_BUS_IS_PHYS (1)

#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE

static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index a4fc3f4..b259956 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -597,26 +597,6 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
return start;
}

-int pci_mmap_page_range(struct pci_dev *dev, int bar,
- struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- if (mmap_state == pci_mmap_io)
- return -EINVAL;
-
- /*
- * Mark this as IO
- */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
-}
-
void __init pci_map_io_early(unsigned long pfn)
{
struct map_desc pci_io_desc = {
--
2.9.3

Tony Luck

unread,
Apr 12, 2017, 5:50:09 PM4/12/17
to
On Wed, Apr 12, 2017 at 5:26 AM, David Woodhouse <dw...@infradead.org> wrote:
> From: David Woodhouse <dw...@amazon.co.uk>
>
> Now that we eliminated the different behaviour in separately-reviewable
> commits, we can switch IA64 to the generic implementation.
>
> Signed-off-by: David Woodhouse <dw...@amazon.co.uk>

Well it builds and boots on my last remaining ia64 machine. No warnings
or weird stuff in the console log. So you can mark the three ia64 patches

Tested-by: Tony Luck <tony...@intel.com>

and bundle them with the others rather than through the ia64 tree.

-Tony

Thomas Gleixner

unread,
Apr 12, 2017, 6:00:05 PM4/12/17
to
On Wed, 12 Apr 2017, Tony Luck wrote:

> On Wed, Apr 12, 2017 at 5:26 AM, David Woodhouse <dw...@infradead.org> wrote:
> > From: David Woodhouse <dw...@amazon.co.uk>
> >
> > Now that we eliminated the different behaviour in separately-reviewable
> > commits, we can switch IA64 to the generic implementation.
> >
> > Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
>
> Well it builds and boots on my last remaining ia64 machine.

Does that mean ia64 reached the 'NCR Voyager' stage and can be scheduled
for removal?

Thanks,

tglx

Jesper Nilsson

unread,
Apr 13, 2017, 3:40:09 AM4/13/17
to
On Wed, Apr 12, 2017 at 01:26:01PM +0100, David Woodhouse wrote:
> From: David Woodhouse <dw...@amazon.co.uk>
>
> Signed-off-by: David Woodhouse <dw...@amazon.co.uk>

For the CRIS part:

Acked-by: Jesper Nilsson <jesper....@axis.com>
/^JN - Jesper Nilsson
--
Jesper Nilsson -- jesper....@axis.com

David Woodhouse

unread,
Apr 13, 2017, 4:40:04 AM4/13/17
to
On Wed, 2017-04-12 at 14:47 -0700, Tony Luck wrote:
> On Wed, Apr 12, 2017 at 5:26 AM, David Woodhouse <dw...@infradead.org> wrote:
> >
> > From: David Woodhouse <dw...@amazon.co.uk>
> >
> > Now that we eliminated the different behaviour in separately-reviewable
> > commits, we can switch IA64 to the generic implementation.
> >
> > Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
>
> Well it builds and boots on my last remaining ia64 machine. No warnings
> or weird stuff in the console log.  So you can mark the three ia64 patches

Thanks. The interesting test is whether you can correctly map PCI BARs
through /proc/bus/pci and /sys/bus/pci?

And if you find a prefetchable BAR you can scribble on, does the box
explode if you do it both WC and UC at the same time?

http://david.woodhou.se/pcimmap_copy.c should validate WC mappings and
look something like this...

[fedora@ip-172-31-55-194 ~]$ sudo ./pcimmap_copy /sys/bus/pci/devices/0000\:00\:1e.0/resource4 0
Copied 1000 loops in 0.354437301s
[fedora@ip-172-31-55-194 ~]$ sudo ./pcimmap_copy /sys/bus/pci/devices/0000\:00\:1e.0/resource4_wc 0
Copied 1000 loops in 0.057309254s

David Woodhouse

unread,
Apr 13, 2017, 4:50:04 AM4/13/17
to
On Thu, 2017-04-13 at 09:37 +0200, Jesper Nilsson wrote:
> On Wed, Apr 12, 2017 at 01:26:01PM +0100, David Woodhouse wrote:
> >
> > From: David Woodhouse <dw...@amazon.co.uk>
> >
> > Signed-off-by: David Woodhouse <dw...@amazon.co.uk>
> For the CRIS part:
>
> Acked-by: Jesper Nilsson <jesper....@axis.com>

Thanks. I actually had that once before but it had got lost in the
refactoring. Added back now.

David Howells

unread,
Apr 13, 2017, 5:30:08 AM4/13/17
to
David Woodhouse <dw...@infradead.org> wrote:

> + vma->vm_pgoff += (pci_resource_start(pdev, bar) >> PAGE_SHIFT);
> + vma->vm_ops = &pci_phys_vm_ops;

Whitespace error.

David

David Howells

unread,
Apr 13, 2017, 5:30:16 AM4/13/17
to
David Woodhouse <dw...@infradead.org> wrote:

> From: David Woodhouse <dw...@amazon.co.uk>
>
> This was setting vma->vm_flags |= VM_LOCKED. Not sure why...
>
> Signed-off-by: David Woodhouse <dw...@amazon.co.uk>

Reviewed-by: David Howells <dhow...@redhat.com>

Bjorn Helgaas

unread,
Apr 18, 2017, 2:30:05 PM4/18/17
to
On Wed, Apr 12, 2017 at 01:25:49PM +0100, David Woodhouse wrote:
> This pursues my previous patch set all the way to its logical conclusion.
>
> It kills off the legacy arch-provided pci_mmap_page_range() completely,
> along with its vile 'address converted by pci_resource_to_user()' API
> and the various bugs and other strange behaviour that various
> architectures had.
>
> In some cases like IA64 I've killed off the odd behaviour *first* in
> separately reviewable patches, before the final switch over to the
> generic code which should then basically have no functional effect.
>
> To accommodate the ARM64 maintainers' desire *not* to support mmap
> through /proc/bus/pci I have separated HAVE_PCI_MMAP from the sysfs
> implementation, which (as of the last patch in the series) ends up
> present on *all* platforms with an MMU. I still don't think that's a
> *good* idea though; it's a generic part of /proc, and nobody ever did
> answer my question about what *else* we can delete from /proc on ARM64
> "because it's a new platform"...
>
> I would very much like the interesting parts of this to go through the
> arch maintainers' trees. I'd suggest that we can pull everything up to
> and including patch 19 ("pci: Add I/O BAR support to generic
> pci_mmap_resource_range()") through the PCI tree, which includes the
> relatively trivial architectures. Then the others can go through the
> appropriate arch tree with more careful review and testing.
>
> Once everything's done, then we can apply something like the final
> patch ("pci: Kill ARCH_GENERIC_PCI_MMAP_RESOURCE"). But that's mostly
> just there for now as a demonstration of the intended end point.
>
> This is in
> git://git.infradead.org/users/dwmw2/random-2.6.git pcimmap
> http://git.infradead.org/users/dwmw2/random-2.6.git/shortlog/refs/heads/pcimmap

Applied to pci/resource-mmap for v4.12, thanks!

This consists of the email patches + the acks/etc so far. It doesn't
include any updates from your git branch (but it doesn't look like it's
been updated recently).

> David Woodhouse (27):
> pci: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
> pci: Fix another sanity check bug in /proc/pci mmap
> pci: Only allow WC mmap on prefetchable resources
> xtensa: Do not mmap PCI BARs to userspace as write-through
> pci: Add arch_can_pci_mmap_wc() macro
> pci: Move multiple declarations of pci_mmap_page_range() to
> <linux/pci.h>
> pci: Add arch_can_pci_mmap_io() on architectures which can mmap() I/O
> space
> pci: Use BAR index in sysfs attr->private instead of resource pointer
> pci: Add BAR index argument to pci_mmap_page_range()
> pci: Add pci_mmap_resource_range() and use it for ARM64
> arm: Use generic pci_mmap_resource_range()
> cris: Use generic pci_mmap_resource_range()
> mips: Use generic pci_mmap_resource_range()
> mn10300: Use generic pci_mmap_resource_range()
> parisc: Use generic pci_mmap_resource_range()
> sh: Use generic pci_mmap_resource_range()
> unicore: Use generic pci_mmap_resource_range()
> x86: Use generic pci_mmap_resource_range()
> pci: Add I/O BAR support to generic pci_mmap_resource_range()
> powerpc: Use generic pci_mmap_resource_range()
> microblaze: Use generic pci_mmap_resource_range()
> xtensa: Use generic pci_mmap_resource_range()
> ia64: Remove redundant valid_mmap_phys_addr_range() from
> pci_mmap_page_range()
> ia64: Remove redundant checks for WC in pci_mmap_page_range()
> ia64: Use generic pci_mmap_resource_range()
> sparc: Use generic pci_mmap_resource_range()
> pci: Kill ARCH_GENERIC_PCI_MMAP_RESOURCE
>
> Documentation/filesystems/sysfs-pci.txt | 12 ++-
> arch/arm/include/asm/pci.h | 2 -
> arch/arm/kernel/bios32.c | 19 ----
> arch/cris/arch-v32/drivers/pci/bios.c | 22 -----
> arch/cris/include/asm/pci.h | 3 -
> arch/ia64/include/asm/pci.h | 4 +-
> arch/ia64/pci/pci.c | 46 ----------
> arch/microblaze/include/asm/pci.h | 8 +-
> arch/microblaze/pci/pci-common.c | 99 ++------------------
> arch/mips/include/asm/pci.h | 4 -
> arch/mips/pci/pci.c | 24 -----
> arch/mn10300/include/asm/pci.h | 3 -
> arch/mn10300/unit-asb2305/pci-asb2305.c | 23 -----
> arch/parisc/include/asm/pci.h | 3 -
> arch/parisc/kernel/pci.c | 28 ------
> arch/powerpc/include/asm/pci.h | 9 +-
> arch/powerpc/kernel/pci-common.c | 105 +++-------------------
> arch/sh/drivers/pci/pci.c | 21 -----
> arch/sh/include/asm/pci.h | 3 +-
> arch/sparc/include/asm/pci_64.h | 5 +-
> arch/sparc/kernel/pci.c | 155 --------------------------------
> arch/unicore32/include/asm/pci.h | 2 -
> arch/unicore32/kernel/pci.c | 23 -----
> arch/x86/include/asm/pci.h | 6 +-
> arch/x86/pci/i386.c | 47 ----------
> arch/xtensa/include/asm/pci.h | 9 +-
> arch/xtensa/kernel/pci.c | 112 ++---------------------
> drivers/pci/Makefile | 1 +
> drivers/pci/mmap.c | 67 ++++++++++++++
> drivers/pci/pci-sysfs.c | 76 +++++++---------
> drivers/pci/pci.h | 4 +-
> drivers/pci/proc.c | 41 ++++++---
> include/linux/pci.h | 30 +++++++
> 33 files changed, 211 insertions(+), 805 deletions(-)
> create mode 100644 drivers/pci/mmap.c
>
> --
> 2.9.3
>

Bjorn Helgaas

unread,
Apr 18, 2017, 3:00:06 PM4/18/17
to
Oops, sorry, I just noticed your desired merge process above.

I removed everything after patch 19 from my branch, so it now contains
these patches:

e34bedcbfa71 PCI: Add I/O BAR support to generic pci_mmap_resource_range()
4f27eb90214b x86/PCI: Use generic pci_mmap_resource_range()
192702a91cdc unicore32/PCI: Use generic pci_mmap_resource_range()
11c9d07f5a48 sh/PCI: Use generic pci_mmap_resource_range()
c18dc595e36c parisc: Use generic pci_mmap_resource_range()
f8773c830087 mn10300/PCI: Use generic pci_mmap_resource_range()
93ec50f6955d MIPS: PCI: Use generic pci_mmap_resource_range()
e47765a11a38 cris/PCI: Use generic pci_mmap_resource_range()
a2f4dd2b148b ARM/PCI: Use generic pci_mmap_resource_range()
9f97f5c8fb0e PCI: Add pci_mmap_resource_range() and use it for ARM64
4536661783d8 PCI: Add BAR index argument to pci_mmap_page_range()
3e07a66fe61c PCI: Use BAR index in sysfs attr->private instead of resource pointer
416a332dcf00 pci: Add arch_can_pci_mmap_io() on architectures which can mmap() I/O space
11df19546fe4 PCI: Move multiple declarations of pci_mmap_page_range() to <linux/pci.h>
ae749c7ab475 PCI: Add arch_can_pci_mmap_wc() macro
03a064b431eb xtensa/PCI: Do not mmap PCI BARs to userspace as write-through
cef4d02305a0 PCI: Only allow WC mmap on prefetchable resources
17caf5673131 PCI: Fix another sanity check bug in /proc/pci mmap
6bccc7f426ab PCI: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms

David Woodhouse

unread,
Apr 19, 2017, 3:30:06 AM4/19/17
to
On Tue, 2017-04-18 at 13:28 -0500, Bjorn Helgaas wrote:
>
> Applied to pci/resource-mmap for v4.12, thanks!
>
> This consists of the email patches + the acks/etc so far.  It doesn't
> include any updates from your git branch (but it doesn't look like it's
> been updated recently).

Thanks. Aside from merging the acks, I had also fixed a typo in
include/linux/pci.h (s/aroudn/around) and re-ordered the later commits
to put the three IA64 changes immediately after the ones you already
merged. Tony said it was OK to take those through your tree too.

I've taken your pci/resource-mmap branch, edited it to apply the typo
fix, and added the three IA64 commits at

 git://git.infradead.org/users/dwmw2/random-2.6.git for-bjorn
http://git.infradead.org/users/dwmw2/random-2.6.git/shortlog/refs/heads/for-bjorn

Bjorn Helgaas

unread,
Apr 19, 2017, 2:40:05 PM4/19/17
to
I pulled this branch; it's on my pci/resource-mmap branch for v4.12.
0 new messages