Skip to content

Commit

Permalink
Merge branch 'pci/resource-mmap' into next
Browse files Browse the repository at this point in the history
* pci/resource-mmap:
  ia64: Use generic pci_mmap_resource_range()
  ia64: Remove redundant checks for WC in pci_mmap_page_range()
  ia64: Remove redundant valid_mmap_phys_addr_range() from pci_mmap_page_range()
  PCI: Add I/O BAR support to generic pci_mmap_resource_range()
  x86/PCI: Use generic pci_mmap_resource_range()
  unicore32/PCI: Use generic pci_mmap_resource_range()
  sh/PCI: Use generic pci_mmap_resource_range()
  parisc: Use generic pci_mmap_resource_range()
  mn10300/PCI: Use generic pci_mmap_resource_range()
  MIPS: PCI: Use generic pci_mmap_resource_range()
  cris/PCI: Use generic pci_mmap_resource_range()
  ARM/PCI: Use generic pci_mmap_resource_range()
  PCI: Add pci_mmap_resource_range() and use it for ARM64
  PCI: Add BAR index argument to pci_mmap_page_range()
  PCI: Use BAR index in sysfs attr->private instead of resource pointer
  PCI: Add arch_can_pci_mmap_io() on architectures which can mmap() I/O space
  PCI: Move multiple declarations of pci_mmap_page_range() to <linux/pci.h>
  PCI: Add arch_can_pci_mmap_wc() macro
  xtensa/PCI: Do not mmap PCI BARs to userspace as write-through
  PCI: Only allow WC mmap on prefetchable resources
  PCI: Fix another sanity check bug in /proc/pci mmap
  PCI: Fix pci_mmap_fits() for HAVE_PCI_RESOURCE_TO_USER platforms
  • Loading branch information
Bjorn Helgaas committed Apr 28, 2017
2 parents 78f0983 + d9c102d commit 889e4dd
Show file tree
Hide file tree
Showing 34 changed files with 238 additions and 385 deletions.
15 changes: 12 additions & 3 deletions Documentation/filesystems/sysfs-pci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,18 @@ 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
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
Expand Down
3 changes: 1 addition & 2 deletions arch/arm/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ 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);
#define ARCH_GENERIC_PCI_MMAP_RESOURCE

static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
Expand Down
19 changes: 0 additions & 19 deletions arch/arm/kernel/bios32.c
Original file line number Diff line number Diff line change
Expand Up @@ -597,25 +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, 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 = {
Expand Down
2 changes: 2 additions & 0 deletions arch/arm64/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 0 additions & 22 deletions arch/cris/arch-v32/drivers/pci/bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +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, 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)
Expand Down
4 changes: 1 addition & 3 deletions arch/cris/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ 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);

#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

Expand Down
5 changes: 3 additions & 2 deletions arch/ia64/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ extern unsigned long ia64_max_iommu_merge_mask;
#define PCI_DMA_BUS_IS_PHYS (ia64_max_iommu_merge_mask == ~0UL)

#define HAVE_PCI_MMAP
extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
#define ARCH_GENERIC_PCI_MMAP_RESOURCE
#define arch_can_pci_mmap_wc() 1

#define HAVE_PCI_LEGACY
extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
struct vm_area_struct *vma,
Expand Down
46 changes: 0 additions & 46 deletions arch/ia64/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,52 +418,6 @@ pcibios_align_resource (void *data, const struct resource *res,
return res->start;
}

int
pci_mmap_page_range (struct pci_dev *dev, 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.
*/
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 (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
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))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
else
vma->vm_page_prot = 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
Expand Down
6 changes: 2 additions & 4 deletions arch/microblaze/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,10 @@ 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
#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);
Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/pci/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
5 changes: 1 addition & 4 deletions arch/mips/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,7 @@ extern unsigned long PCIBIOS_MIN_MEM;
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 ARCH_GENERIC_PCI_MMAP_RESOURCE
#define HAVE_ARCH_PCI_RESOURCE_TO_USER

/*
Expand Down
24 changes: 0 additions & 24 deletions arch/mips/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +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, 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);
}
4 changes: 1 addition & 3 deletions arch/mn10300/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ 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);
#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __KERNEL__ */

Expand Down
23 changes: 0 additions & 23 deletions arch/mn10300/unit-asb2305/pci-asb2305.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,26 +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, 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;

return 0;
}
4 changes: 1 addition & 3 deletions arch/parisc/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,6 @@ 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);
#define ARCH_GENERIC_PCI_MMAP_RESOURCE

#endif /* __ASM_PARISC_PCI_H */
28 changes: 0 additions & 28 deletions arch/parisc/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,34 +227,6 @@ 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,
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;

if (write_combine)
return -EINVAL;

/*
* Ignore write-combine; for now only return uncached mappings.
*/
prot = pgprot_val(vma->vm_page_prot);
prot |= _PAGE_NO_CACHE;
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);
}

/*
* A driver is enabling the device. We make sure that all the appropriate
* bits are set to allow the device to operate as the driver is expecting.
Expand Down
9 changes: 4 additions & 5 deletions arch/powerpc/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,11 @@ 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
/* 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,
size_t count);
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/kernel/pci-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,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 =
Expand Down
21 changes: 0 additions & 21 deletions arch/sh/drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,27 +269,6 @@ 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,
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,
Expand Down
4 changes: 2 additions & 2 deletions arch/sh/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ 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);
#define ARCH_GENERIC_PCI_MMAP_RESOURCE

extern void pcibios_set_master(struct pci_dev *dev);

/* Dynamic DMA mapping stuff.
Expand Down
5 changes: 1 addition & 4 deletions arch/sparc/include/asm/pci_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,10 @@ 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

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;
Expand Down
Loading

0 comments on commit 889e4dd

Please sign in to comment.