aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/pci
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2007-07-11 13:02:15 -0400
committerTony Luck <tony.luck@intel.com>2007-07-11 14:34:49 -0400
commit012b7105cc816fb797eb1c161cdfc0052b5c3f53 (patch)
tree084ede189a3284c17f09ea68d0d4573d95e7499f /arch/ia64/pci
parent9e121327b37b751ef66e6f57e2d02dd568955148 (diff)
[IA64] prevent MCA when performing MMIO mmap to PCI config space
Example memory map (HP rx7640 with 'default' acpiconfig setting, VGA disabled): 0x00000000 - 0x3FFFBFFF supports only WB (cacheable) access If a user attempts to perform an MMIO mmap (using the PCIIOC_MMAP_IS_MEM ioctl) to PCI config space (like mmap'ing and accessing memory at 0xA0000), we will MCA because the kernel will attempt to use a mapping with the UC attribute. So check the memory attribute in kern_mmap and the EFI memmap. If WC is requested, and WC or UC access is supported for the region, allow it. Otherwise, use the same attribute the kernel uses. Updates documentation and test cases as well. Signed-off-by: Alex Chiang <achiang@hp.com> Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/pci')
-rw-r--r--arch/ia64/pci/pci.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 73696b4a2eed..07d0e92742c8 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -591,6 +591,9 @@ int
591pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, 591pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
592 enum pci_mmap_state mmap_state, int write_combine) 592 enum pci_mmap_state mmap_state, int write_combine)
593{ 593{
594 unsigned long size = vma->vm_end - vma->vm_start;
595 pgprot_t prot;
596
594 /* 597 /*
595 * I/O space cannot be accessed via normal processor loads and 598 * I/O space cannot be accessed via normal processor loads and
596 * stores on this platform. 599 * stores on this platform.
@@ -604,15 +607,24 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
604 */ 607 */
605 return -EINVAL; 608 return -EINVAL;
606 609
610 if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
611 return -EINVAL;
612
613 prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
614 vma->vm_page_prot);
615
607 /* 616 /*
608 * Leave vm_pgoff as-is, the PCI space address is the physical 617 * If the user requested WC, the kernel uses UC or WC for this region,
609 * address on this platform. 618 * and the chipset supports WC, we can use WC. Otherwise, we have to
619 * use the same attribute the kernel uses.
610 */ 620 */
611 if (write_combine && efi_range_is_wc(vma->vm_start, 621 if (write_combine &&
612 vma->vm_end - vma->vm_start)) 622 ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC ||
623 (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) &&
624 efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
613 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 625 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
614 else 626 else
615 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 627 vma->vm_page_prot = prot;
616 628
617 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 629 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
618 vma->vm_end - vma->vm_start, vma->vm_page_prot)) 630 vma->vm_end - vma->vm_start, vma->vm_page_prot))