0ad722f159
The ARCH_GENERIC_PCI_MMAP_RESOURCE symbol came up in a recent discussion, and I noticed that this was left behind by an unfinished cleanup from 2017. The only architecture that still relies on providing its own pci_mmap_page_range() helper instead of using the generic pci_mmap_resource_range() is sparc. Presumably the reasons for this have not changed, but at least this can be simplified by converting sparc to use the same interface as the others. The only difference between the two is the device-specific offset that gets added to or subtracted from vma->vm_pgoff. Change the only caller of pci_mmap_page_range() in common code to subtract this offset and call the modern interface, while adding it back in the sparc implementation to preserve the existing behavior. This removes the complexities of the dual interfaces from the common code, and keeps it all specific to the sparc architecture code. According to David Miller, the sparc code lets user space poke into the VGA I/O port registers by mmapping the I/O space of the parent bridge device, which is something that the generic pci_mmap_resource_range() code apparently does not. Link: https://lore.kernel.org/lkml/1519887203.622.3.camel@infradead.org/t/ Link: https://lore.kernel.org/lkml/20220714214657.2402250-3-shorne@gmail.com/ Link: https://lore.kernel.org/r/20220715153617.3393420-1-arnd@kernel.org Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: David Woodhouse <dwmw2@infradead.org> Cc: David S. Miller <davem@davemloft.net> Cc: Stafford Horne <shorne@gmail.com>
53 lines
1.2 KiB
C
53 lines
1.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Generic PCI resource mmap helper
|
|
*
|
|
* Copyright © 2017 Amazon.com, Inc. or its affiliates.
|
|
*
|
|
* Author: David Woodhouse <dwmw2@infradead.org>
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/pci.h>
|
|
|
|
#ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
|
|
|
|
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;
|
|
int ret;
|
|
|
|
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);
|
|
|
|
if (mmap_state == pci_mmap_io) {
|
|
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,
|
|
vma->vm_end - vma->vm_start,
|
|
vma->vm_page_prot);
|
|
}
|
|
|
|
#endif
|