IOMMU Fixes for Linux v5.3-rc4
Including: - 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. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEr9jSbILcajRFYWYyK/BELZcBGuMFAl1UFQIACgkQK/BELZcB GuNW1A//Y86ZFRSVCA/+ZiHgADwqsof1/Cdc1Ou1tXMbINbyWvWyT5t8JtplYsEJ 17xlS7l2M9x1VCljzr3fTfBMGu8+CQY2KT6YJliLQZzrQ6LKoxmscCmg6DmH4Gjy CfoRLBXCKTm1F8aNt7f/XupuI+OGpq8h/VPDxYqZZIGKxsMfOH8ZIzF7DjDO2MxS NROjwAyVMZdzR5X/dM1dYK0zwxQvgRGEx8gdGssoyUCJvGdAyQXym30j8esNWJ6J okXVpuQoX/CJQLZP/xF8psWcL+0IJSyd3G90ToBRsoLDc50a4qTdelGvGkVHmU8L WVm+x7GjJrWZieqUtFnW/X7p4qSZdNMIK9c/+/cKg+BxyAKE9FqUJzg6UaSpzTbk XVh0jSiSq7/txU8pyGhEDQxgg4xbIUA5x1gqnqFm8k9Noz1/+AhfdyEUFzIHeE0s XwBfVVGzP2NW5zi97NebEuYsbHgDDSnR9sEKxhhq6G30vrwHEfg/MzdvNp6EupNp J1DnWD0DgMlYMxjZ8YskrSI7/MFB5PCxj/InwAXRZmlPPmlWIRTJfUtwYmhlkoLS zCxfS/sIof9C1pU7noe1WwOz8ylVPeQO3KvBIVhy3WJcVnCDlYX7/Uf/z/sU/d0Z Hd3/PQ6F6xTUEBzXKOFG/3y9EUQuoYP/fckFM4vmH9OEvYWmWqc= =+b4H -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
b5e33e44d9
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue