Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 085ff82c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/iommu-2.6:
  intel-iommu: Don't use identity mapping for PCI devices behind bridges
  intel-iommu: Use iommu_should_identity_map() at startup time too.
  intel-iommu: No mapping for non-PCI devices
  intel-iommu: Restore DMAR_BROKEN_GFX_WA option for broken graphics drivers
  intel-iommu: Add iommu_should_identity_map() function
  intel-iommu: Fix reattaching of devices to identity mapping domain
  intel-iommu: Don't set identity mapping for bypassed graphics devices
  intel-iommu: Fix dma vs. mm page confusion with aligned_nrpages()
parents f63bafe5 3dfc813d
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -1913,6 +1913,18 @@ config DMAR_DEFAULT_ON
	  recommended you say N here while the DMAR code remains
	  experimental.

config DMAR_BROKEN_GFX_WA
	def_bool n
	prompt "Workaround broken graphics drivers (going away soon)"
	depends on DMAR
	---help---
	  Current Graphics drivers tend to use physical address
	  for DMA and avoid using DMA APIs. Setting this config
	  option permits the IOMMU driver to set a unity map for
	  all the OS-visible memory. Hence the driver can continue
	  to use physical addresses for DMA, at least until this
	  option is removed in the 2.6.32 kernel.

config DMAR_FLOPPY_WA
	def_bool y
	depends on DMAR
+83 −23
Original line number Diff line number Diff line
@@ -2117,6 +2117,47 @@ static int domain_add_dev_info(struct dmar_domain *domain,
	return 0;
}

static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
{
	if (iommu_identity_mapping == 2)
		return IS_GFX_DEVICE(pdev);

	/*
	 * We want to start off with all devices in the 1:1 domain, and
	 * take them out later if we find they can't access all of memory.
	 *
	 * However, we can't do this for PCI devices behind bridges,
	 * because all PCI devices behind the same bridge will end up
	 * with the same source-id on their transactions.
	 *
	 * Practically speaking, we can't change things around for these
	 * devices at run-time, because we can't be sure there'll be no
	 * DMA transactions in flight for any of their siblings.
	 * 
	 * So PCI devices (unless they're on the root bus) as well as
	 * their parent PCI-PCI or PCIe-PCI bridges must be left _out_ of
	 * the 1:1 domain, just in _case_ one of their siblings turns out
	 * not to be able to map all of memory.
	 */
	if (!pdev->is_pcie) {
		if (!pci_is_root_bus(pdev->bus))
			return 0;
		if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
			return 0;
	} else if (pdev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
		return 0;

	/* 
	 * At boot time, we don't yet know if devices will be 64-bit capable.
	 * Assume that they will -- if they turn out not to be, then we can 
	 * take them out of the 1:1 domain later.
	 */
	if (!startup)
		return pdev->dma_mask > DMA_BIT_MASK(32);

	return 1;
}

static int iommu_prepare_static_identity_mapping(void)
{
	struct pci_dev *pdev = NULL;
@@ -2127,6 +2168,7 @@ static int iommu_prepare_static_identity_mapping(void)
		return -EFAULT;

	for_each_pci_dev(pdev) {
		if (iommu_should_identity_map(pdev, 1)) {
			printk(KERN_INFO "IOMMU: identity mapping for device %s\n",
			       pci_name(pdev));

@@ -2138,6 +2180,7 @@ static int iommu_prepare_static_identity_mapping(void)
			if (ret)
				return ret;
		}
	}

	return 0;
}
@@ -2291,6 +2334,10 @@ int __init init_dmars(void)
	 * identity mapping if iommu_identity_mapping is set.
	 */
	if (!iommu_pass_through) {
#ifdef CONFIG_DMAR_BROKEN_GFX_WA
		if (!iommu_identity_mapping)
			iommu_identity_mapping = 2;
#endif
		if (iommu_identity_mapping)
			iommu_prepare_static_identity_mapping();
		/*
@@ -2368,15 +2415,15 @@ error:
	return ret;
}

/* Returns a number of VTD pages, but aligned to MM page size */
static inline unsigned long aligned_nrpages(unsigned long host_addr,
					    size_t size)
{
	host_addr &= ~PAGE_MASK;
	host_addr += size + PAGE_SIZE - 1;

	return host_addr >> VTD_PAGE_SHIFT;
	return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
}

/* This takes a number of _MM_ pages, not VTD pages */
static struct iova *intel_alloc_iova(struct device *dev,
				     struct dmar_domain *domain,
				     unsigned long nrpages, uint64_t dma_mask)
@@ -2443,16 +2490,24 @@ static int iommu_dummy(struct pci_dev *pdev)
}

/* Check if the pdev needs to go through non-identity map and unmap process.*/
static int iommu_no_mapping(struct pci_dev *pdev)
static int iommu_no_mapping(struct device *dev)
{
	struct pci_dev *pdev;
	int found;

	if (unlikely(dev->bus != &pci_bus_type))
		return 1;

	pdev = to_pci_dev(dev);
	if (iommu_dummy(pdev))
		return 1;

	if (!iommu_identity_mapping)
		return iommu_dummy(pdev);
		return 0;

	found = identity_mapping(pdev);
	if (found) {
		if (pdev->dma_mask > DMA_BIT_MASK(32))
		if (iommu_should_identity_map(pdev, 0))
			return 1;
		else {
			/*
@@ -2469,9 +2524,12 @@ static int iommu_no_mapping(struct pci_dev *pdev)
		 * In case of a detached 64 bit DMA device from vm, the device
		 * is put into si_domain for identity mapping.
		 */
		if (pdev->dma_mask > DMA_BIT_MASK(32)) {
		if (iommu_should_identity_map(pdev, 0)) {
			int ret;
			ret = domain_add_dev_info(si_domain, pdev);
			if (ret)
				return 0;
			ret = domain_context_mapping(si_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
			if (!ret) {
				printk(KERN_INFO "64bit %s uses identity mapping\n",
				       pci_name(pdev));
@@ -2480,7 +2538,7 @@ static int iommu_no_mapping(struct pci_dev *pdev)
		}
	}

	return iommu_dummy(pdev);
	return 0;
}

static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
@@ -2496,7 +2554,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,

	BUG_ON(dir == DMA_NONE);

	if (iommu_no_mapping(pdev))
	if (iommu_no_mapping(hwdev))
		return paddr;

	domain = get_valid_domain_for_dev(pdev);
@@ -2506,7 +2564,8 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
	iommu = domain_get_iommu(domain);
	size = aligned_nrpages(paddr, size);

	iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
	iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
				pdev->dma_mask);
	if (!iova)
		goto error;

@@ -2635,7 +2694,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
	struct iova *iova;
	struct intel_iommu *iommu;

	if (iommu_no_mapping(pdev))
	if (iommu_no_mapping(dev))
		return;

	domain = find_domain(pdev);
@@ -2726,7 +2785,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
	struct iova *iova;
	struct intel_iommu *iommu;

	if (iommu_no_mapping(pdev))
	if (iommu_no_mapping(hwdev))
		return;

	domain = find_domain(pdev);
@@ -2785,7 +2844,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
	struct intel_iommu *iommu;

	BUG_ON(dir == DMA_NONE);
	if (iommu_no_mapping(pdev))
	if (iommu_no_mapping(hwdev))
		return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);

	domain = get_valid_domain_for_dev(pdev);
@@ -2797,7 +2856,8 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
	for_each_sg(sglist, sg, nelems, i)
		size += aligned_nrpages(sg->offset, sg->length);

	iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
	iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
				pdev->dma_mask);
	if (!iova) {
		sglist->dma_length = 0;
		return 0;