Merge branch 'pci/resource'
- Replace sparc pci_mmap_page_range() wrapper. This still leaves a sparc-specific pci_mmap_resource_range(), but it's only one interface instead of two (Arnd Bergmann) - Remove sparc-specific pci_mmap_resource_range() by implementing pci_iobar_pfn(). This removes the ability to map the entire PCI I/O space using /proc/bus/pci, but we believe that's already been broken since v2.6.28 (Arnd Bergmann) * pci/resource: sparc: Use generic pci_mmap_resource_range() PCI: Remove pci_mmap_page_range() wrapper
This commit is contained in:
commit
bac0f4474c
|
@ -125,7 +125,7 @@ implementation of that functionality. To support the historical interface of
|
||||||
mmap() through files in /proc/bus/pci, platforms may also set HAVE_PCI_MMAP.
|
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
|
Alternatively, platforms which set HAVE_PCI_MMAP may provide their own
|
||||||
implementation of pci_mmap_page_range() instead of defining
|
implementation of pci_mmap_resource_range() instead of defining
|
||||||
ARCH_GENERIC_PCI_MMAP_RESOURCE.
|
ARCH_GENERIC_PCI_MMAP_RESOURCE.
|
||||||
|
|
||||||
Platforms which support write-combining maps of PCI resources must define
|
Platforms which support write-combining maps of PCI resources must define
|
||||||
|
|
|
@ -37,6 +37,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
|
||||||
#define HAVE_PCI_MMAP
|
#define HAVE_PCI_MMAP
|
||||||
#define arch_can_pci_mmap_io() 1
|
#define arch_can_pci_mmap_io() 1
|
||||||
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
|
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
|
||||||
|
#define ARCH_GENERIC_PCI_MMAP_RESOURCE
|
||||||
#define get_pci_unmapped_area get_fb_unmapped_area
|
#define get_pci_unmapped_area get_fb_unmapped_area
|
||||||
#endif /* CONFIG_SPARC64 */
|
#endif /* CONFIG_SPARC64 */
|
||||||
|
|
||||||
|
|
|
@ -751,156 +751,15 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Platform support for /proc/bus/pci/X/Y mmap()s. */
|
/* Platform support for /proc/bus/pci/X/Y mmap()s. */
|
||||||
|
int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
|
||||||
/* 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;
|
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
|
||||||
unsigned long space_size, user_offset, user_size;
|
resource_size_t ioaddr = pci_resource_start(pdev, bar);
|
||||||
|
|
||||||
if (mmap_state == pci_mmap_io) {
|
if (!pbm)
|
||||||
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;
|
return -EINVAL;
|
||||||
|
|
||||||
if (mmap_state == pci_mmap_io) {
|
vma->vm_pgoff += (ioaddr + pbm->io_space.start) >> PAGE_SHIFT;
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,27 +13,6 @@
|
||||||
|
|
||||||
#ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
|
#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)
|
|
||||||
{
|
|
||||||
resource_size_t start, end;
|
|
||||||
|
|
||||||
pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end);
|
|
||||||
|
|
||||||
/* Adjust vm_pgoff to be the offset within the resource */
|
|
||||||
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 = {
|
static const struct vm_operations_struct pci_phys_vm_ops = {
|
||||||
#ifdef CONFIG_HAVE_IOREMAP_PROT
|
#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||||
.access = generic_access_phys,
|
.access = generic_access_phys,
|
||||||
|
@ -70,27 +49,4 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
|
||||||
vma->vm_page_prot);
|
vma->vm_page_prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Legacy setup: Implement 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
|
#endif
|
||||||
|
|
|
@ -244,6 +244,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_dev *dev = pde_data(file_inode(file));
|
||||||
struct pci_filp_private *fpriv = file->private_data;
|
struct pci_filp_private *fpriv = file->private_data;
|
||||||
|
resource_size_t start, end;
|
||||||
int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;
|
int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_RAWIO) ||
|
if (!capable(CAP_SYS_RAWIO) ||
|
||||||
|
@ -278,7 +279,11 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
iomem_is_exclusive(dev->resource[i].start))
|
iomem_is_exclusive(dev->resource[i].start))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ret = pci_mmap_page_range(dev, i, vma,
|
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
|
||||||
|
|
||||||
|
/* Adjust vm_pgoff to be the offset within the resource */
|
||||||
|
vma->vm_pgoff -= start >> PAGE_SHIFT;
|
||||||
|
ret = pci_mmap_resource_range(dev, i, vma,
|
||||||
fpriv->mmap_state, write_combine);
|
fpriv->mmap_state, write_combine);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1909,24 +1909,14 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
|
||||||
|
|
||||||
#include <asm/pci.h>
|
#include <asm/pci.h>
|
||||||
|
|
||||||
/* These two functions provide almost identical functionality. Depending
|
/*
|
||||||
* on the architecture, one will be implemented as a wrapper around the
|
|
||||||
* other (in drivers/pci/mmap.c).
|
|
||||||
*
|
|
||||||
* pci_mmap_resource_range() maps a specific BAR, and vm->vm_pgoff
|
* pci_mmap_resource_range() maps a specific BAR, and vm->vm_pgoff
|
||||||
* is expected to be an offset within that region.
|
* 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,
|
int pci_mmap_resource_range(struct pci_dev *dev, int bar,
|
||||||
struct vm_area_struct *vma,
|
struct vm_area_struct *vma,
|
||||||
enum pci_mmap_state mmap_state, int write_combine);
|
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);
|
|
||||||
|
|
||||||
#ifndef arch_can_pci_mmap_wc
|
#ifndef arch_can_pci_mmap_wc
|
||||||
#define arch_can_pci_mmap_wc() 0
|
#define arch_can_pci_mmap_wc() 0
|
||||||
|
|
Loading…
Reference in New Issue