Commit bac0f447 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents 3dc4d333 c1ef3224
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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 */

+4 −145
Original line number Diff line number Diff line
@@ -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;

	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;
	resource_size_t ioaddr = pci_resource_start(pdev, bar);

		/* 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)
	if (!pbm)
		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;
}
+0 −44
Original line number Diff line number Diff line
@@ -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
+6 −1
Original line number Diff line number Diff line
@@ -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;
Loading