mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 11:06:41 -05:00
Merge tag 'iommu-fixes-v6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux
Pull iommu fixes from Joerg Roedel: "ARM-SMMU fixes: - Fix broken detection of the S2FWB feature - Ensure page-size bitmap is initialised for SVA domains - Fix handling of SMMU client devices with duplicate Stream IDs - Don't fail SMMU probe if Stream IDs are aliased across clients Intel VT-d fixes: - Add quirk for IGFX device - Revert an ATS change to fix a boot failure AMD IOMMU: - Fix potential buffer overflow Core: - Fix for iommu_copy_struct_from_user()" * tag 'iommu-fixes-v6.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux: iommu/vt-d: Apply quirk_iommu_igfx for 8086:0044 (QM57/QS57) iommu/vt-d: Revert ATS timing change to fix boot failure iommu: Fix two issues in iommu_copy_struct_from_user() iommu/amd: Fix potential buffer overflow in parse_ivrs_acpihid iommu/arm-smmu-v3: Fail aliasing StreamIDs more gracefully iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated stream ids iommu/arm-smmu-v3: Fix pgsize_bit for sva domains iommu/arm-smmu-v3: Add missing S2FWB feature detection
This commit is contained in:
@@ -3664,6 +3664,14 @@ static int __init parse_ivrs_acpihid(char *str)
|
||||
while (*uid == '0' && *(uid + 1))
|
||||
uid++;
|
||||
|
||||
if (strlen(hid) >= ACPIHID_HID_LEN) {
|
||||
pr_err("Invalid command line: hid is too long\n");
|
||||
return 1;
|
||||
} else if (strlen(uid) >= ACPIHID_UID_LEN) {
|
||||
pr_err("Invalid command line: uid is too long\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = early_acpihid_map_size++;
|
||||
memcpy(early_acpihid_map[i].hid, hid, strlen(hid));
|
||||
memcpy(early_acpihid_map[i].uid, uid, strlen(uid));
|
||||
|
||||
@@ -411,6 +411,12 @@ struct iommu_domain *arm_smmu_sva_domain_alloc(struct device *dev,
|
||||
return ERR_CAST(smmu_domain);
|
||||
smmu_domain->domain.type = IOMMU_DOMAIN_SVA;
|
||||
smmu_domain->domain.ops = &arm_smmu_sva_domain_ops;
|
||||
|
||||
/*
|
||||
* Choose page_size as the leaf page size for invalidation when
|
||||
* ARM_SMMU_FEAT_RANGE_INV is present
|
||||
*/
|
||||
smmu_domain->domain.pgsize_bitmap = PAGE_SIZE;
|
||||
smmu_domain->smmu = smmu;
|
||||
|
||||
ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
|
||||
|
||||
@@ -3388,6 +3388,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
||||
mutex_lock(&smmu->streams_mutex);
|
||||
for (i = 0; i < fwspec->num_ids; i++) {
|
||||
struct arm_smmu_stream *new_stream = &master->streams[i];
|
||||
struct rb_node *existing;
|
||||
u32 sid = fwspec->ids[i];
|
||||
|
||||
new_stream->id = sid;
|
||||
@@ -3398,11 +3399,21 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
|
||||
break;
|
||||
|
||||
/* Insert into SID tree */
|
||||
if (rb_find_add(&new_stream->node, &smmu->streams,
|
||||
arm_smmu_streams_cmp_node)) {
|
||||
dev_warn(master->dev, "stream %u already in tree\n",
|
||||
sid);
|
||||
ret = -EINVAL;
|
||||
existing = rb_find_add(&new_stream->node, &smmu->streams,
|
||||
arm_smmu_streams_cmp_node);
|
||||
if (existing) {
|
||||
struct arm_smmu_master *existing_master =
|
||||
rb_entry(existing, struct arm_smmu_stream, node)
|
||||
->master;
|
||||
|
||||
/* Bridged PCI devices may end up with duplicated IDs */
|
||||
if (existing_master == master)
|
||||
continue;
|
||||
|
||||
dev_warn(master->dev,
|
||||
"Aliasing StreamID 0x%x (from %s) unsupported, expect DMA to be broken\n",
|
||||
sid, dev_name(existing_master->dev));
|
||||
ret = -ENODEV;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4429,6 +4440,8 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
|
||||
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3);
|
||||
if (FIELD_GET(IDR3_RIL, reg))
|
||||
smmu->features |= ARM_SMMU_FEAT_RANGE_INV;
|
||||
if (FIELD_GET(IDR3_FWB, reg))
|
||||
smmu->features |= ARM_SMMU_FEAT_S2FWB;
|
||||
|
||||
/* IDR5 */
|
||||
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
|
||||
|
||||
@@ -3785,20 +3785,6 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
|
||||
|
||||
intel_iommu_debugfs_create_dev(info);
|
||||
|
||||
/*
|
||||
* The PCIe spec, in its wisdom, declares that the behaviour of the
|
||||
* device is undefined if you enable PASID support after ATS support.
|
||||
* So always enable PASID support on devices which have it, even if
|
||||
* we can't yet know if we're ever going to use it.
|
||||
*/
|
||||
if (info->pasid_supported &&
|
||||
!pci_enable_pasid(pdev, info->pasid_supported & ~1))
|
||||
info->pasid_enabled = 1;
|
||||
|
||||
if (sm_supported(iommu))
|
||||
iommu_enable_pci_ats(info);
|
||||
iommu_enable_pci_pri(info);
|
||||
|
||||
return &iommu->iommu;
|
||||
free_table:
|
||||
intel_pasid_free_table(dev);
|
||||
@@ -3810,6 +3796,26 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void intel_iommu_probe_finalize(struct device *dev)
|
||||
{
|
||||
struct device_domain_info *info = dev_iommu_priv_get(dev);
|
||||
struct intel_iommu *iommu = info->iommu;
|
||||
|
||||
/*
|
||||
* The PCIe spec, in its wisdom, declares that the behaviour of the
|
||||
* device is undefined if you enable PASID support after ATS support.
|
||||
* So always enable PASID support on devices which have it, even if
|
||||
* we can't yet know if we're ever going to use it.
|
||||
*/
|
||||
if (info->pasid_supported &&
|
||||
!pci_enable_pasid(to_pci_dev(dev), info->pasid_supported & ~1))
|
||||
info->pasid_enabled = 1;
|
||||
|
||||
if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev))
|
||||
iommu_enable_pci_ats(info);
|
||||
iommu_enable_pci_pri(info);
|
||||
}
|
||||
|
||||
static void intel_iommu_release_device(struct device *dev)
|
||||
{
|
||||
struct device_domain_info *info = dev_iommu_priv_get(dev);
|
||||
@@ -4391,6 +4397,7 @@ const struct iommu_ops intel_iommu_ops = {
|
||||
.domain_alloc_sva = intel_svm_domain_alloc,
|
||||
.domain_alloc_nested = intel_iommu_domain_alloc_nested,
|
||||
.probe_device = intel_iommu_probe_device,
|
||||
.probe_finalize = intel_iommu_probe_finalize,
|
||||
.release_device = intel_iommu_release_device,
|
||||
.get_resv_regions = intel_iommu_get_resv_regions,
|
||||
.device_group = intel_iommu_device_group,
|
||||
@@ -4432,6 +4439,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx);
|
||||
|
||||
/* QM57/QS57 integrated gfx malfunctions with dmar */
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_iommu_igfx);
|
||||
|
||||
/* Broadwell igfx malfunctions with dmar */
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx);
|
||||
@@ -4509,7 +4519,6 @@ static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
|
||||
}
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
|
||||
|
||||
|
||||
@@ -440,10 +440,10 @@ static inline int __iommu_copy_struct_from_user(
|
||||
void *dst_data, const struct iommu_user_data *src_data,
|
||||
unsigned int data_type, size_t data_len, size_t min_len)
|
||||
{
|
||||
if (src_data->type != data_type)
|
||||
return -EINVAL;
|
||||
if (WARN_ON(!dst_data || !src_data))
|
||||
return -EINVAL;
|
||||
if (src_data->type != data_type)
|
||||
return -EINVAL;
|
||||
if (src_data->len < min_len || data_len < src_data->len)
|
||||
return -EINVAL;
|
||||
return copy_struct_from_user(dst_data, data_len, src_data->uptr,
|
||||
@@ -456,8 +456,8 @@ static inline int __iommu_copy_struct_from_user(
|
||||
* include/uapi/linux/iommufd.h
|
||||
* @user_data: Pointer to a struct iommu_user_data for user space data info
|
||||
* @data_type: The data type of the @kdst. Must match with @user_data->type
|
||||
* @min_last: The last memember of the data structure @kdst points in the
|
||||
* initial version.
|
||||
* @min_last: The last member of the data structure @kdst points in the initial
|
||||
* version.
|
||||
* Return 0 for success, otherwise -error.
|
||||
*/
|
||||
#define iommu_copy_struct_from_user(kdst, user_data, data_type, min_last) \
|
||||
|
||||
Reference in New Issue
Block a user