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.
|
||||
|
||||
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.
|
||||
|
||||
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 arch_can_pci_mmap_io() 1
|
||||
#define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
|
||||
#define ARCH_GENERIC_PCI_MMAP_RESOURCE
|
||||
#define get_pci_unmapped_area get_fb_unmapped_area
|
||||
#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. */
|
||||
|
||||
/* 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)
|
||||
int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
|
||||
{
|
||||
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) {
|
||||
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)
|
||||
if (!pbm)
|
||||
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;
|
||||
vma->vm_pgoff += (ioaddr + pbm->io_space.start) >> PAGE_SHIFT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,27 +13,6 @@
|
||||
|
||||
#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 = {
|
||||
#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||
.access = generic_access_phys,
|
||||
@ -70,27 +49,4 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
|
||||
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
|
||||
|
@ -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_filp_private *fpriv = file->private_data;
|
||||
resource_size_t start, end;
|
||||
int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;
|
||||
|
||||
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))
|
||||
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);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -1909,24 +1909,14 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
|
||||
|
||||
#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
|
||||
* 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);
|
||||
|
||||
#ifndef arch_can_pci_mmap_wc
|
||||
#define arch_can_pci_mmap_wc() 0
|
||||
|
Loading…
Reference in New Issue
Block a user