Commit b5e33e44 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'iommu-fixes-v5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull iommu fixes from Joerg Roedel:

 - A couple more fixes for the Intel VT-d driver for bugs introduced
   during the recent conversion of this driver to use IOMMU core default
   domains.

 - Fix for common dma-iommu code to make sure MSI mappings happen in the
   correct domain for a device.

 - Fix a corner case in the handling of sg-lists in dma-iommu code that
   might cause dma_length to be truncated.

 - Mark a switch as fall-through in arm-smmu code.

* tag 'iommu-fixes-v5.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/vt-d: Fix possible use-after-free of private domain
  iommu/vt-d: Detach domain before using a private one
  iommu/dma: Handle SG length overflow better
  iommu/vt-d: Correctly check format of page table in debugfs
  iommu/vt-d: Detach domain when move device out of group
  iommu/arm-smmu: Mark expected switch fall-through
  iommu/dma: Handle MSI mappings separately
parents cab6d5b6 3a18844d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1186,7 +1186,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
			ste_live = true;
			break;
		case STRTAB_STE_0_CFG_ABORT:
			if (disable_bypass)
			BUG_ON(!disable_bypass);
			break;
		default:
			BUG(); /* STE corruption */
+11 −8
Original line number Diff line number Diff line
@@ -459,13 +459,11 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
{
	struct iommu_domain *domain = iommu_get_dma_domain(dev);
	struct iommu_dma_cookie *cookie = domain->iova_cookie;
	size_t iova_off = 0;
	struct iova_domain *iovad = &cookie->iovad;
	size_t iova_off = iova_offset(iovad, phys);
	dma_addr_t iova;

	if (cookie->type == IOMMU_DMA_IOVA_COOKIE) {
		iova_off = iova_offset(&cookie->iovad, phys);
		size = iova_align(&cookie->iovad, size + iova_off);
	}
	size = iova_align(iovad, size + iova_off);

	iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
	if (!iova)
@@ -764,7 +762,7 @@ static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents,
		 * - and wouldn't make the resulting output segment too long
		 */
		if (cur_len && !s_iova_off && (dma_addr & seg_mask) &&
		    (cur_len + s_length <= max_len)) {
		    (max_len - cur_len >= s_length)) {
			/* ...then concatenate it with the previous one */
			cur_len += s_length;
		} else {
@@ -1147,16 +1145,21 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
	if (!msi_page)
		return NULL;

	iova = __iommu_dma_map(dev, msi_addr, size, prot);
	if (iova == DMA_MAPPING_ERROR)
	iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
	if (!iova)
		goto out_free_page;

	if (iommu_map(domain, iova, msi_addr, size, prot))
		goto out_free_iova;

	INIT_LIST_HEAD(&msi_page->list);
	msi_page->phys = msi_addr;
	msi_page->iova = iova;
	list_add(&msi_page->list, &cookie->msi_page_list);
	return msi_page;

out_free_iova:
	iommu_dma_free_iova(cookie, iova, size);
out_free_page:
	kfree(msi_page);
	return NULL;
+1 −1
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ static void ctx_tbl_walk(struct seq_file *m, struct intel_iommu *iommu, u16 bus)
		tbl_wlk.ctx_entry = context;
		m->private = &tbl_wlk;

		if (pasid_supported(iommu) && is_pasid_enabled(context)) {
		if (dmar_readq(iommu->reg + DMAR_RTADDR_REG) & DMA_RTADDR_SMT) {
			pasid_dir_ptr = context->lo & VTD_PAGE_MASK;
			pasid_dir_size = get_pasid_dir_size(context);
			pasid_dir_walk(m, pasid_dir_ptr, pasid_dir_size);
+9 −2
Original line number Diff line number Diff line
@@ -3449,6 +3449,7 @@ static bool iommu_need_mapping(struct device *dev)
				dmar_domain = to_dmar_domain(domain);
				dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
			}
			dmar_remove_one_dev_info(dev);
			get_private_domain_for_dev(dev);
		}

@@ -4790,7 +4791,8 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info)

	/* free the private domain */
	if (domain->flags & DOMAIN_FLAG_LOSE_CHILDREN &&
	    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY))
	    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
	    list_empty(&domain->devices))
		domain_exit(info->domain);

	free_devinfo_mem(info);
@@ -4803,6 +4805,7 @@ static void dmar_remove_one_dev_info(struct device *dev)

	spin_lock_irqsave(&device_domain_lock, flags);
	info = dev->archdata.iommu;
	if (info)
		__dmar_remove_one_dev_info(info);
	spin_unlock_irqrestore(&device_domain_lock, flags);
}
@@ -5281,6 +5284,7 @@ static int intel_iommu_add_device(struct device *dev)
		if (device_def_domain_type(dev) == IOMMU_DOMAIN_IDENTITY) {
			ret = iommu_request_dm_for_dev(dev);
			if (ret) {
				dmar_remove_one_dev_info(dev);
				dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
				domain_add_dev_info(si_domain, dev);
				dev_info(dev,
@@ -5291,6 +5295,7 @@ static int intel_iommu_add_device(struct device *dev)
		if (device_def_domain_type(dev) == IOMMU_DOMAIN_DMA) {
			ret = iommu_request_dma_domain_for_dev(dev);
			if (ret) {
				dmar_remove_one_dev_info(dev);
				dmar_domain->flags |= DOMAIN_FLAG_LOSE_CHILDREN;
				if (!get_private_domain_for_dev(dev)) {
					dev_warn(dev,
@@ -5316,6 +5321,8 @@ static void intel_iommu_remove_device(struct device *dev)
	if (!iommu)
		return;

	dmar_remove_one_dev_info(dev);

	iommu_group_remove_device(dev);

	iommu_device_unlink(&iommu->iommu, dev);